Posts Tagged ‘security’

sign(data, SHA256withRSA) != sign(hash, NONEwithRSA)

Quite funny that after a few months offline I find the fun in writing a small article about an investigation which is still about security.

My task was to find how I could replicate the signature performed with an old applet and a proprietary library which used a hardware token in javascript using a new api provided by a different party.

The old applet just signed a hash and I had to find the way to implement this with the new api.

signOld(hash) = signJS(hash, mechanism) where mechanism is a CKM_* (CKM_SHA256_RSA_PKCS, CKM_RSA_PKCS, etc) in PKCS terms.

I am skipping the part where I had to confirm that the same keys are used.

The ebics applet does sign(hash) where hash is a precomputed SHA-256 hash of the data. This led me first to try the CKM_SHA256_RSA_PKCS and CKM_RSA_PKCS mechanisms to replicate the signature in the new api however:

signOld(hash) != signjs(hash, mechanism)

After some investigation (applet decompilation) I confirmed that:

sign(hash) = Signature(hash, "SHA256withRSA")

but still:

signOld(hash) != signjs(hash, CKM_SHA256_RSA_PKCS)

The applet used a custom JCE to connect to the hardware token and after more digging I realized
the Digest impl was replaced with a custom digest which did if fact only an Identity. So:

signOld(hash) = Signature(hash, "SHA256withRSA") where SHA256(data) = data*. 

Not even now:

signOld(hash) != signjs(hash, CKM_RSA_PKCS)

this is due to the fact (EUREKA) that in fact:

Signature(data, SHA256withRSA) = RSA(OID(SHA256) || SHA256(data)) 

(see the RFC https://tools.ietf.org/html/rfc3447#section-9.2) which in our case was:

signOld(hash) = RSA(OID(SHA256) || Identity(data)).

This solved the issue as:

signOld(hash) = signjs(OID(SHA256) || hash, CKM_RSA_PKCS)

and OID(SHA256) = “3031300d060960864801650304020105000420”

So instead of signing the first line I should have signed the second in order to replicate the old behaviour

fb059955cdc2d5d8f2a3ee78664966576696b7173f14df67031ebe9b63074c84
3031300d060960864801650304020105000420fb059955cdc2d5d8f2a3ee78664966576696b7173f14df67031ebe9b63074c84

So the interesting result is that:

sign(data, SHA256withRSA) != sign(SHA256(data), NONEwithRSA)

Attach payload into detached pkcs#7 signature

If you are doing signature generation via a hardware token (for instance 3Skey) then, for large files it is impractical to send the file to the hardware token. Instead you send a hash (SHA256), get a detached PKCS#7 signature and you need to re-attach the payload in java code. For once this was easier to do with plain JCE code instead of my favorite BouncyCastle provider. However for really large files BC does provide the streaming mechanism required.

Of course the best commands to use to help debug the code bellow are:

Verify pkcs#7 signature

#the -noverify means do not verify the certificate chain, this will only verify the signature not the originating certificate
openssl smime -inform DER -verify -noverify -in signature.p7s

(more…)

openssl recipes

These last days I had to tinker with openssl a lot and this is a short memory reminder of the params.

PKCS#7 manipulation

Verify pkcs#7 signature

#the -noverify means do not verify the certificate chain, this will only verify the signature not the originating certificate
openssl smime -inform DER -verify -noverify -in signature.p7s

Show the structure of the file (applies to all DER files)

#for debuging
openssl asn1parse -inform DER -i -in signature.p7s

Extract certificate and public key

openssl pkcs7 -inform DER -in signature.p7s -print_certs > certificate.crt
openssl x509 -in certificate.crt -noout -pubkey > pubKey.key

JKS certificate import

Export private key from jks keystore

#convert jks to pkcs#12 format
keytool -importkeystore -srckeystore myKeystore.jks -destkeystore myKeystore.p12
-deststoretype PKCS12 -srcalias myAlias
#export private key (WARNING, manipulate with care)
openssl pkcs12 -in myKeystore.p12  -nodes -nocerts -out myKey.pem

Check .csr or .crt public key against a private key

This will generate the sha256 hash for the public key, compare manualy. Very useful if you lost your key or are getting “No certificate matches private key”.

#generate hash for pubKey generated from privateKey
openssl pkey -in myPrivateKey.key -pubout -outform pem | sha256sum 
#generate hash for pubKey from cert
openssl x509 -in myCertificate.crt -pubkey -noout -outform pem | sha256sum 
#generate hash for pubKey from csr
openssl req -in myCSR.csr -pubkey -noout -outform pem | sha256sum

Convert p7b signed certificate response to jks keystore

This is very useful if you lost your jks keystore containing the original .csr

#export certs from signed certificate response to .pem
openssl pkcs7 -print_certs -in myStore.p7b -out certs.pem
#combine certs and key in pkcs#12 format
openssl pkcs12 -export -name server -in certs.pem -out myKeystore.p12 -inkey myPrivateKey.key
#convert pkcs#12 to jks
keytool -importkeystore -srcstoretype pkcs12 -srckeystore myKeystore.p12 -destkeystore myKeystore.jks

Let’s decrypt

AES encrypt in java and decrypt in java, flex, python, C#.

Encrypt: java

public static void encrypt(InputStream is, OutputStream out, String secret) throws Exception {
	SecretKey secretKey = new SecretKeySpec(Hex.decodeHex(secret.toCharArray()), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        out.write(cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV());
        CipherOutputStream cipherOutputStream = new CipherOutputStream(out, cipher);
        int bufLength = KEY_LENGTH/8 * 100;
        byte buf[] = new byte[bufLength];
        int bytesRead = 0;
	while((bytesRead = is.read(buf)) != -1 ) {
		cipherOutputStream.write(buf, 0, bytesRead);
	}
	cipherOutputStream.close();
}

(more…)

A few notes about external hdd encryption

When storing your backups on an external drive you occasionally take with you it is a very good idea to encrypt your backups. Here are some personal conclusions after trying 2 different solutions.

(more…)

A bit of L2TP debuging

The problem was to connect to a L2TP server from linux, no windows available.

(more…)

Openssl example

This is a complete example on how to use openssl to fetch a https page. The example is based on the several others I found on the web so my credit is minimal and only consist of modifying just a little the existing examples to compile and work with openssl-0.9.8e on Linux and Solaris.

The example

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>

#include <iostream>

#define MAX_PACKET_SIZE 10000

int main() {

        BIO * bio;
        SSL * ssl;
        SSL_CTX * ctx;

        /* Initializing OpenSSL */

        SSL_load_error_strings();
        ERR_load_BIO_strings();
        OpenSSL_add_all_algorithms();

        SSL_library_init(); //mandatory and missing from some examples
        ctx = SSL_CTX_new(SSLv23_client_method());

        if (ctx == NULL) {
                std::cout << "Ctx is null" << std::endl;
                ERR_print_errors_fp(stderr);
        }

	//using a store from examples
        if(! SSL_CTX_load_verify_locations(ctx, "/tmp/openssl-0.9.8e/certs/vsign1.pem", NULL))
        {
            /* Handle failed load here */
                std::cout << "Faild load verify locations" << std::endl;

        }

        bio = BIO_new_ssl_connect(ctx);
        BIO_get_ssl(bio, & ssl);
        SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);

        //replace with your own test server
	BIO_set_conn_hostname(bio, "10.0.0.1:443");

        if(BIO_do_connect(bio) <= 0)
        {
                std::cout<<"Failed connection" << std::endl;
                /* Handle failed connection */
        } else {
                std::cout<<"Connected" << std::endl;
        }

        if(SSL_get_verify_result(ssl) != X509_V_OK)
        {
            /* Handle the failed verification */
            std::cout << "Failed get verify result " << std::endl;

            fprintf(stderr, "Certificate verification error: %i\n", SSL_get_verify_result(ssl));
	    //do not exit here (but some more verification would not hurt) because if you are using a self-signed certificate you will receive 18
	    //18 X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT which is not an error
        }

        char *write_buf = "GET / HTTP/1.1\r\nHost: www.nemesisit.ro\r\n\r\n";

        if(BIO_write(bio, write_buf, strlen(write_buf)) <= 0)
        {
                if(! BIO_should_retry(bio))
                {
                        /* Handle failed write here */
                }
            /* Do something to handle the retry */
                std::cout << "Failed write" << std::endl;
        }

        char buf[MAX_PACKET_SIZE];

        int p;
        char r[1024];
        for(;;)
        {
                p = BIO_read(bio, r, 1023);
                if(p <= 0) break;
                r[p] = 0;
                printf("%s", r);
        }

        std::cout << "Done reading" << std::endl;

        /* To free it from memory, use this line */

        ERR_print_errors_fp(stderr);
        BIO_free_all(bio);

        return 0;
}

Compilation

Linux:

g++ -I/tmp/openssl-0.9.8e/include -L/tmp/openssl-0.9.8e client_ssl.cc -ldl -lssl -lcrypto  -o client_ssl

Solaris:

CC client_ssl.cc -I/tmp/openssl-0.9.8e/include -L/tmp/openssl-0.9.8e -ldl -lssl -lcrypto -lnsl -lsocket  -o client_ssl