RSA – Matching OpenSSL Signature w/ Chilkat

The following problem is common. The goal is to match the signature produced by this OpenSSL command w/ Chilkat:

cat in.txt | openssl dgst -sha1 -sign myPrivateKey.pem | openssl enc -base64

The “gotcha” is when the input text file ends with a linefeed character (a single byte having value 0x0A), but the programmer does not realize it. The bytes passed to the openssl dgst command must be exactly the same on both sides. Therefore, if the input file ends with a 0x0A (linefeed), then the bytes passed to the Chilkat RSA’s EncryptStringENC method must also include the linefeed. Be careful to match the line endings on both sides (Chilkat and OpenSSL) — i.e. don’t use CRLF on one side but a bare-LF on the other…

Create Amazon CloudFront Signed URL in VBScript (for ASP)

This sample code snippet is graciously provided by a Chilkat customer:

See Also: Chilkat RSA ActiveX Reference Documentation

...

resource = "http://*********.cloudfront.net/something.jpg"

'Expiration
expiration = 1278680686

'Policy
policy = "{""Statement"":[{""Resource"":""" &  resource & _
    """,""Condition"":{""DateLessThan"":{""AWS:EpochTime"":" & _
   expiration & "}}}]}"

'Chilkat Component
set pkey = Server.CreateObject("Chilkat.PrivateKey")

'Load the private key from an RSA PEM file:
private_key = pkey.LoadPemFile("c:\pk-xxx.pem")

'Get the private key in XML format:
private_key = pkey.GetXml()

set rsa = Server.CreateObject("Chilkat.Rsa")

'Any string argument automatically begins the 30-day trial.
success = rsa.UnlockComponent("30-day trial")
If (success <> 1) Then
    response.write("RSA component unlock failed<br><br>")
End If

'Import the private key into the RSA component:
success = rsa.ImportPrivateKey(private_key)
If (success <> 1) Then
    response.write("Error: " & rsa.LastErrorText & "<br><br>")
End If

rsa.Charset = "utf-8"
rsa.EncodingMode = "base64"
rsa.LittleEndian = 0
signature = rsa.SignStringENC(policy,"sha-1")

'UrlSafe
signature = Replace(signature,"+","-")
signature = Replace(signature,"=","_")
signature = Replace(signature,"/","~")

signedUrl = "" & resource & "?Expires=" & expiration & "&Signature=" & signature & _
    "&Key-Pair-Id=" & key_pair_id

response.write("<img src=""" & signedUrl & """ />")

set pkey = nothing
set rsa = nothing

...

Saving an RSA key pair to a file

Question:

I’m having trouble finding a good/complete VB.Net Chilkat example of how to generate an RSA key container with a key pair (private and public) and save that key container to a file.

Answer:

I think I can clarify.  With 2 points:

1) In actuality, an RSA private key also contains the public-part of the key.  It contains the all of the key parts:  modulus, exponent, D, P, Q, DP, DQ, and InverseQ.  The public key is really just a sub-set of the private key and is composed of the modulus and exponent.  Therefore, to save the key pair, you really only need to save the private key.

2) The “key container” in a file would be an encrypted or unencrypted PEM (text) or DER (binary) file.  Either can be PCKS8 format or “RSA” format.  You would use the Chilkat.PrivateKey file to save the private key to PEM or DER (see the reference docs).  You may export the private key from the Chilkat.Rsa class to an XML string, and then load it into the Chilkat.PrivateKey class, and then save it to a file in whichever format you desire, using encryption or not.

Java Create Signature / Chilkat Verify Interoperability

The following Java code produces a digital signature that can be verified using Chilkat RSA.  Links to the Chilkat signature verification examples follow this code.  The Java signature creation code does not use Chilkat to produce the digital signature.  It also demonstrates how to save a generated key (public and private) to DER files that can be used with Chilkat RSA.

import java.io.*;
import java.security.*;

// Chilkat is only used for Base64 and Hex encoding.
import com.chilkatsoft.*;

public class SignTest {

  static {
    try {
        System.loadLibrary("chilkat");
    } catch (UnsatisfiedLinkError e) {
      System.err.println("Native code library failed to load.\n" + e);
      System.exit(1);
    }
  }

  public static void main(String argv[])
  {
  	  try
  	  {
		KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
		System.out.println("Generated RSA Key!");
		generator.initialize(1024);
		KeyPair keyPair = generator.generateKeyPair();

		PrivateKey privKey = keyPair.getPrivate();
		PublicKey pubKey = keyPair.getPublic();

		// Save the private key to an ASN.1 DER file:
		byte[] privKeyDer = privKey.getEncoded();
		OutputStream outPrivKey = new FileOutputStream("privKey.der");
		outPrivKey.write(privKeyDer);
		outPrivKey.close();

		// Save the public key to an ASN.1 DER file:
		byte[] pubKeyDer = pubKey.getEncoded();
		OutputStream outPubKey = new FileOutputStream("pubKey.der");
		outPubKey.write(pubKeyDer);
		outPubKey.close();

		Signature _signature = Signature.getInstance("SHA1withRSA");
		_signature.initSign(privKey);

		// Sign the string "The quick brown fox jumps over the lazy dog"
		String strToSign = "The quick brown fox jumps over the lazy dog";
		byte[] bytesToSign = strToSign.getBytes();
		_signature.update(bytesToSign,0,bytesToSign.length);

        // If you signed a string with characters in non-English languages, you may
        // wish to see the exact bytes signed, perhaps by loading the following file
        // in a hex editor.  Make sure the program verifying the signature uses the same
        // byte representations for the characters (i.e. the same character encoding).
		OutputStream outBytesSigned = new FileOutputStream("bytesToSign.txt");
		outBytesSigned.write(bytesToSign);
		outBytesSigned.close();

		// Sign the contents of a file with this commented-out code:
		//FileInputStream fis = new FileInputStream("dude.gif");
		//BufferedInputStream bufin = new BufferedInputStream(fis);
		//byte[] buffer = new byte[1024];
		//int len;
		//while ((len = bufin.read(buffer)) >= 0) {
			//_signature.update(buffer, 0, len);
			//};
		//bufin.close();

		// Create the signature.
		byte[] sigBytes = _signature.sign();

		OutputStream out = new FileOutputStream("sig.dat");
		out.write(sigBytes);
		out.close();

		// Convert the signature to a Base64 or hex string:
		CkByteData ckSigBytes = new CkByteData();
    	ckSigBytes.appendByteArray(sigBytes);

	    //  Convert to hexidecimalized string:
	    System.out.println(ckSigBytes.getEncoded("hex"));

	    //  Convert to base64 string:
	    System.out.println(ckSigBytes.getEncoded("base64"));

		System.out.println("Success!");

	    //} catch (NoSuchProviderException e) {
	    //	System.out.println("NoSuchProviderException!");
	    } catch (IOException e) {
	    	System.out.println("IOException!");
	    } catch (InvalidKeyException e) {
	    	System.out.println("InvalidKeyException!");
		} catch (SignatureException e) {
			System.out.println("SignatureException!");
		} catch (NoSuchAlgorithmException e) {
	    	System.out.println("NoSuchAlgorithmException!");
			}

  }
}

Verify Digital Signature examples using Chilkat in various programming languages:
ASP: Verify Java Signature
SQL Server: Verify Java Signature
C#: Verify Java Signature
C++: Verify Java Signature
MFC: Verify Java Signature
C: Verify Java Signature
Delphi: Verify Java Signature
Visual FoxPro: Verify Java Signature
Java: Verify Java Signature
Perl: Verify Java Signature
PHP: Verify Java Signature
Python: Verify Java Signature
Ruby: Verify Java Signature
VB.NET: Verify Java Signature
Visual Basic: Verify Java Signature
VBScript: Verify Java Signature

Chilkat 9.0.2 Release Notes

RSA

  • Fixed PEM to XML conversion so that XML is compatible with .NET Framework’s XML requirements.
  • Fixed RSA key generation. In some cases, RSA generated keys were not valid.
  • Verified key acceptance and signature matching between Chilkat, OpenSSL, and .NET

MIME / DKIM

  • Fixed DKIM and DomainKeys signature generation.
  • Tested and verified DKIM / DomainKeys signatures in emails sent to port25.com and yahoo.com.

OAEP Padding vs. PKCS v1.5 Padding Error

This error occurs if RSA encrypted data using OAEP padding is decrypted with the assumption that PKCS v1.5 padding was used. To solve the problem, set the OaepPadding property = true prior to decrypting.


RSA_decrypt:
KeyType: Private
InputSize: 128
Padding: PKCS v1.5
ModulusBitLen: 1024
Invalid PKCS v1.5 padding header (1)
FoundBlockType: 197
ExpectingBlockType: 2