4.9 Java Code to Sign a Sample Proprietary Certificate Hash

The following Java code illustrates how to sign a Proprietary Certificate Hash with RSA.

 import java.math.BigInteger;
  
 public class RdpRsaSign
 {
     //
     // Print out the contents of a byte array in hexadecimal.
     //
     private static void PrintBytes(
         byte[] bytes
         )
     {
         int cBytes = bytes.length;
         int iByte = 0;
  
         for (;;) {
             for (int i = 0; i < 8; i++) {
                 String hex = Integer.toHexString(bytes[iByte++] & 0xff);
                 if (hex.length() == 1) {
                     hex = "0" + hex;
                 }
  
                 System.out.print("0x" + hex + " ");
                 if (iByte >= cBytes) {
                     System.out.println();
                     return;
                 }
             }
             System.out.println();
         }
     }
  
     //
     // Reverse the order of the values in a byte array.
     //
     public static void ReverseByteArray(
         byte[] array
         )
     {
         int i, j;
         byte temp;
  
         for (i = 0, j = array.length - 1; i < j; i++, j--) {
             temp = array[i];
             array[i] = array[j];
             array[j] = temp;
         }        
     }
  
     //
     // Use RSA to encrypt data.
     //
     public static byte[] RsaEncrypt(
         byte[] modulusBytes,
         byte[] exponentBytes,
         byte[] dataBytes
         )
     {
         //
         // Reverse the passed in byte arrays and then use these to 
         // create the BigIntegers for the RSA computation.
         //
         ReverseByteArray(modulusBytes);
         ReverseByteArray(exponentBytes);
         ReverseByteArray(dataBytes);
  
         BigInteger modulus = new BigInteger(
             1, 
             modulusBytes
             );
         BigInteger exponent = new BigInteger(
             1, 
             exponentBytes
             );
         BigInteger data = new BigInteger(
             1, 
             dataBytes
             );
  
         //
         // Perform RSA encryption: 
         // ciphertext = plaintext^exponent % modulus.
         //
         BigInteger cipherText = data.modPow(
             exponent, 
             modulus
             );
  
         //
         // Reverse the generated ciphertext.
         //
         byte[] cipherTextBytes = cipherText.toByteArray();
         ReverseByteArray(cipherTextBytes);
  
         //
         // Undo the reversal of the passed in byte arrays.
         //
         ReverseByteArray(modulusBytes);
         ReverseByteArray(exponentBytes);
         ReverseByteArray(dataBytes);
  
         return cipherTextBytes;
     }
    
     //
     // Use RSA to decrypt data.
     //
     public static byte[] RsaDecrypt(
         byte[] modulusBytes,
         byte[] privateExponentBytes,
         byte[] encryptedDataBytes
         )
     {
         //
         // Reverse the passed in byte arrays and then use these to 
         // create the BigIntegers for the RSA computation.
         //
         ReverseByteArray(modulusBytes);
         ReverseByteArray(privateExponentBytes);
         ReverseByteArray(encryptedDataBytes);
  
         BigInteger modulus = new BigInteger(
             1, 
             modulusBytes
             );
         BigInteger privateExponent = new BigInteger(
             1, 
             privateExponentBytes
             );
         BigInteger encryptedData = new BigInteger(
             1, 
             encryptedDataBytes
             );
  
         //
         // Perform RSA encryption: 
         // plaintext = ciphertext^privateExponent % modulus.
         //
         BigInteger decryptedData = encryptedData.modPow(
             privateExponent, 
             modulus
             );
  
         //
         // Reverse the generated plaintext.
         //
         byte[] decryptedDataBytes = decryptedData.toByteArray();
         ReverseByteArray(decryptedDataBytes);
  
         //
         // Undo the reversal of the passed in byte arrays.
         //
         ReverseByteArray(modulusBytes);
         ReverseByteArray(privateExponentBytes);
         ReverseByteArray(encryptedDataBytes);
  
         return decryptedDataBytes;
     }
  
     //
     // Main routine.
     //
     public static void main(
         String[] args
         )
     {
         //
         // Modulus bytes obtained straight from the wire in the 
         // proprietary certificate (in little endian format). 
         // This is for a 512-bit key set.
         //
         byte[] modulusBytes = 
         {        
             (byte) 0x3d, (byte) 0x3a, (byte) 0x5e, (byte) 0xbd, 
             (byte) 0x72, (byte) 0x43, (byte) 0x3e, (byte) 0xc9, 
             (byte) 0x4d, (byte) 0xbb, (byte) 0xc1, (byte) 0x1e, 
             (byte) 0x4a, (byte) 0xba, (byte) 0x5f, (byte) 0xcb, 
             (byte) 0x3e, (byte) 0x88, (byte) 0x20, (byte) 0x87, 
             (byte) 0xef, (byte) 0xf5, (byte) 0xc1, (byte) 0xe2, 
             (byte) 0xd7, (byte) 0xb7, (byte) 0x6b, (byte) 0x9a, 
             (byte) 0xf2, (byte) 0x52, (byte) 0x45, (byte) 0x95, 
             (byte) 0xce, (byte) 0x63, (byte) 0x65, (byte) 0x6b, 
             (byte) 0x58, (byte) 0x3a, (byte) 0xfe, (byte) 0xef, 
             (byte) 0x7c, (byte) 0xe7, (byte) 0xbf, (byte) 0xfe, 
             (byte) 0x3d, (byte) 0xf6, (byte) 0x5c, (byte) 0x7d, 
             (byte) 0x6c, (byte) 0x5e, (byte) 0x06, (byte) 0x09, 
             (byte) 0x1a, (byte) 0xf5, (byte) 0x61, (byte) 0xbb, 
             (byte) 0x20, (byte) 0x93, (byte) 0x09, (byte) 0x5f, 
             (byte) 0x05, (byte) 0x6d, (byte) 0xea, (byte) 0x87, 
         };
  
         //
         // Exponent bytes (in little endian order) obtained straight 
         // from the wire (in the proprietary certificate).
         //
         byte[] exponentBytes = 
         {        
             (byte) 0x5b, (byte) 0x7b, (byte) 0x88, (byte) 0xc0
         };
  
         //
         // Private exponent of the private key generated by the 
         // server (in little endian format).
         //
         byte[] privateExponentBytes = 
         {
             (byte) 0x87, (byte) 0xa7, (byte) 0x19, (byte) 0x32, 
             (byte) 0xda, (byte) 0x11, (byte) 0x87, (byte) 0x55, 
             (byte) 0x58, (byte) 0x00, (byte) 0x16, (byte) 0x16, 
             (byte) 0x25, (byte) 0x65, (byte) 0x68, (byte) 0xf8, 
             (byte) 0x24, (byte) 0x3e, (byte) 0xe6, (byte) 0xfa, 
             (byte) 0xe9, (byte) 0x67, (byte) 0x49, (byte) 0x94, 
             (byte) 0xcf, (byte) 0x92, (byte) 0xcc, (byte) 0x33, 
             (byte) 0x99, (byte) 0xe8, (byte) 0x08, (byte) 0x60, 
             (byte) 0x17, (byte) 0x9a, (byte) 0x12, (byte) 0x9f, 
             (byte) 0x24, (byte) 0xdd, (byte) 0xb1, (byte) 0x24, 
             (byte) 0x99, (byte) 0xc7, (byte) 0x3a, (byte) 0xb8, 
             (byte) 0x0a, (byte) 0x7b, (byte) 0x0d, (byte) 0xdd, 
             (byte) 0x35, (byte) 0x07, (byte) 0x79, (byte) 0x17, 
             (byte) 0x0b, (byte) 0x51, (byte) 0x9b, (byte) 0xb3, 
             (byte) 0xc7, (byte) 0x10, (byte) 0x01, (byte) 0x13, 
             (byte) 0xe7, (byte) 0x3f, (byte) 0xf3, (byte) 0x5f
         };
  
         //
         // Sample hash of a proprietary certificate.
         //
         byte[] hashBytes = 
         {
             (byte) 0xf5, (byte) 0xcc, (byte) 0x18, (byte) 0xee, 
             (byte) 0x45, (byte) 0xe9, (byte) 0x4d, (byte) 0xa6,
             (byte) 0x79, (byte) 0x02, (byte) 0xca, (byte) 0x76, 
             (byte) 0x51, (byte) 0x33, (byte) 0xe1, (byte) 0x7f,
             (byte) 0x00, (byte) 0xff, (byte) 0xff, (byte) 0xff, 
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
             (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 
             (byte) 0xff, (byte) 0xff, (byte) 0x01
         };
  
         System.out.println("Hash:");
         PrintBytes(hashBytes);
  
         //
         // Perform decryption (signing).
         //
         byte[] signedHashBytes = RsaDecrypt(
             modulusBytes,
             privateExponentBytes,
             hashBytes
             );        
         
         System.out.println("Signed hash bytes:");
         PrintBytes(signedHashBytes);
     
         //
         // Perform encryption (verification).
         //
         byte[] verifiedHashBytes = RsaEncrypt(
             modulusBytes,
             exponentBytes,
             signedHashBytes
             );        
  
         System.out.println("Verified hash bytes:");
         PrintBytes(verifiedHashBytes);
     }
 };