I am attempting to port a program I wrote using openssl to a Win CE device.
I realize that openssl has not been ported to CE as of yet (in particular
PocketPC, ARM, IPAQ). I really only needed the RSA bit so I tried writing a
shim between the openssl calls that I needed and the Microsoft (gasp!)
Crypto API. I am not much of a windows person and I seem to have hit a
brick wall. Although this is not really an openssl problem it possibly
deals with interoperability between them...
Down to specifics:
So I have gotten to the point where my windows code can encrypt and decrypt
RSA messages by itself. Obviously the code that uses openssl works
correctly as well. However if I encrypt a message and then send it to the
windows device it is unable to decrypt it. At this point my best guess is
the padding, or endianess, but I may be wrong. The CAPI docs don't make it
clear what kind of padding they used, however a google search turns up this:
http://msdn.microsoft.com/library/psdk/crypto/cryptoref1_6tbo.htm
Which doesn't appear to be part of the actual MSDN docs since you can't get
to that page from the root msdn pages. I am not sure if it is some sort of
advanced doc or what. That document indicates that they are using PKCS #1,
type 2. This is probably correct since that is what most people used until
OAEP. I haven't come up with a method of verifying this.
As for endianess... The IPaQ is a little endian machine evidently. CAPI
seems to want/give everything in little endian. My understanding is that
openssl uses all bignums in big endian. Correct me if I am wrong.
The questions are: Am I duplicating work? Is there a better way? What
might I be doing wrong?
Ok, on with the code!
My shim is listed here. Excuse the formatting sloppiness. I stole some
code from Putty which does encryption (but no decryption!) This may be
useful in the future if openssl is ported to CE and makes use of the Crypto
API to do the work (unlikely, but debatable)
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wincrypt.h>
#include <openssl/rsa.h>
extern void perror(char *msg);
/* Large pieces of code shamelessly stolen from Putty */
#define CSP MS_ENHANCED_PROV
HCRYPTPROV hCryptProv;
int RAND_bytes(unsigned char *buf, int num){
return CryptGenRandom(hCryptProv, num, buf);
}
int crypto_startup() {
//CSP
if(CryptAcquireContext(&hCryptProv, NULL, CSP, PROV_RSA_FULL,
CRYPT_NEWKEYSET) == FALSE) {
perror("CryptAcquireContext RSA");
if(GetLastError() == NTE_EXISTS) {
if(CryptAcquireContext(&hCryptProv, NULL, CSP, PROV_RSA_FULL,
0) ==
FALSE) {
perror("Crypt AcquireContext CSP");
return GetLastError();
}
}
else {
perror("Crypt AcquireContext !NTE_EXISTS");
return GetLastError();
}
}
return 0;
}
void crypto_shutdown() {
/*
int i, j;
for(i=0; i<2; i++) {
for(j=0; j<3; j++) {
if(hDESKey[i][j])
CryptDestroyKey(hDESKey[i][j]);
hDESKey[i][j] = 0;
}
}
*/
if(hCryptProv)
CryptReleaseContext(hCryptProv, 0);
hCryptProv = 0;
}
int RSA_public_encrypt(int length, unsigned char *ptext, unsigned char
*ctext, RSA *key, int pad){
/* Not so sure about padding */
int i;
unsigned char *pKeybuf, *pKeyin;
HCRYPTKEY hRsaKey;
PUBLICKEYSTRUC *pBlob;
RSAPUBKEY *pRPK;
unsigned char *buf;
DWORD dlen;
DWORD bufsize;
DWORD mod_size;
mod_size = BN_num_bytes(key->n);
/* allocate buffer for public key blob */
if((pBlob = malloc(sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) +
mod_size)) == NULL){
perror("Out of memory");
return GetLastError();
}
/* allocate buffer for message encryption block */
bufsize = (length + mod_size) << 1;
if((buf = malloc(bufsize)) == NULL){
perror("Out of memory");
return GetLastError();
}
/* construct public key blob from host public key */
pKeybuf = ((unsigned char*)pBlob) + sizeof(PUBLICKEYSTRUC) +
sizeof(RSAPUBKEY);
pKeyin = malloc(mod_size);
BN_bn2bin(key->n, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size; i++)
pKeybuf[i] = pKeyin[mod_size-i-1];
pBlob->bType = PUBLICKEYBLOB;
pBlob->bVersion = 0x02;
pBlob->reserved = 0;
pBlob->aiKeyAlg = CALG_RSA_KEYX;
pRPK = (RSAPUBKEY*)(((unsigned char*)pBlob) + sizeof(PUBLICKEYSTRUC));
pRPK->magic = 0x31415352; /* "RSA1" */
pRPK->bitlen = mod_size * 8;
BN_bn2bin(key->e, pKeyin);
for(i=0; i<BN_num_bytes(key->e); i++)
(&pRPK->pubexp)[i] = pKeyin[BN_num_bytes(key->e)-i-1];
/* import public key blob into key container */
if(CryptImportKey(hCryptProv, (void*)pBlob,
sizeof(PUBLICKEYSTRUC)+sizeof(RSAPUBKEY)+mod_size,
0, 0, &hRsaKey) == 0){
perror("Error importing RSA key!");
return GetLastError();
}
/* copy message into buffer */
memcpy(buf, ptext, length);
dlen = length;
/* using host public key, encrypt the message */
if(CryptEncrypt(hRsaKey, 0, TRUE, 0, buf, &dlen, bufsize) == FALSE){
perror("Error encrypting using RSA key!");
return GetLastError();
}
/*
* For some strange reason, Microsoft CryptEncrypt using public
* key, returns the cyphertext in backwards (little endian)
* order, so reverse it!
*/
for(i = 0; i < (int)dlen; i++)
ctext[i] = buf[dlen - i - 1]; /* make it big endian */
CryptDestroyKey(hRsaKey);
free(buf);
free(pBlob);
free(pKeyin);
return dlen;
}
/*
>From MSDN, Private Key blob:
PUBLICKEYSTRUC publickeystruc ;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8]; (n)
BYTE prime1[rsapubkey.bitlen/16]; (p)
BYTE prime2[rsapubkey.bitlen/16]; (q)
BYTE exponent1[rsapubkey.bitlen/16]; (dmp1)
BYTE exponent2[rsapubkey.bitlen/16]; (dmq1)
BYTE coefficient[rsapubkey.bitlen/16]; (iqmp)
BYTE privateExponent[rsapubkey.bitlen/8]; (d)
other:
public exponent (e)
*/
int RSA_private_decrypt(int length, unsigned char *ctext, unsigned char
*ptext, RSA *key, int pad){
int i;
unsigned char *pKeybuf, *pKeyin;
HCRYPTKEY hRsaKey;
PUBLICKEYSTRUC *pBlob;
RSAPUBKEY *pRPK;
unsigned char *buf;
DWORD dlen;
DWORD bufsize;
DWORD mod_size;
int temp;
mod_size = BN_num_bytes(key->n);
/* allocate buffer for public key blob */
if((pBlob = malloc(sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) +
mod_size + (mod_size/2 * 7))) == NULL){
perror("Out of memory");
return -1;
}
/* allocate buffer for message decryption block */
bufsize = length;
if((buf = malloc(bufsize)) == NULL){
perror("Out of memory");
return -1;
}
/* construct public key blob from host public key */
pKeybuf = ((unsigned char*)pBlob) + sizeof(PUBLICKEYSTRUC) +
sizeof(RSAPUBKEY);
pKeyin = malloc(mod_size);
BN_bn2bin(key->n, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size; i++)
pKeybuf[i] = pKeyin[mod_size-i-1];
pKeybuf += mod_size;
BN_bn2bin(key->p, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size/2; i++)
pKeybuf[i] = pKeyin[mod_size/2-i-1];
pKeybuf += mod_size/2;
BN_bn2bin(key->q, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size/2; i++)
pKeybuf[i] = pKeyin[mod_size/2-i-1];
pKeybuf += mod_size/2;
BN_bn2bin(key->dmp1, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size/2; i++)
pKeybuf[i] = pKeyin[mod_size/2-i-1];
pKeybuf += mod_size/2;
BN_bn2bin(key->dmq1, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size/2; i++)
pKeybuf[i] = pKeyin[mod_size/2-i-1];
pKeybuf += mod_size/2;
BN_bn2bin(key->iqmp, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size/2; i++)
pKeybuf[i] = pKeyin[mod_size/2-i-1];
pKeybuf += mod_size/2;
BN_bn2bin(key->d, pKeyin);
/* change big endian to little endian */
for(i=0; i<mod_size; i++)
pKeybuf[i] = pKeyin[mod_size-i-1];
pKeybuf += mod_size;
pBlob->bType = PRIVATEKEYBLOB;
pBlob->bVersion = 0x02;
pBlob->reserved = 0;
pBlob->aiKeyAlg = CALG_RSA_KEYX;
pRPK = (RSAPUBKEY*)(((unsigned char*)pBlob) + sizeof(PUBLICKEYSTRUC));
pRPK->magic = 0x32415352; /* "RSA2" */
pRPK->bitlen = mod_size * 8;
BN_bn2bin(key->e, pKeyin);
for(i=0; i<BN_num_bytes(key->e); i++)
(&pRPK->pubexp)[i] = pKeyin[BN_num_bytes(key->e)-i-1];
/* import public key blob into key container */
if(CryptImportKey(hCryptProv, (void*)pBlob,
sizeof(PUBLICKEYSTRUC)+sizeof(RSAPUBKEY)+mod_size+(mod_size/2 *
7),
0, CRYPT_EXPORTABLE, &hRsaKey) == FALSE){
perror("Error importing RSA key!");
return GetLastError();
}
dlen = length;
for(i = 0; i < (int)dlen; i++)
buf[i] = ctext[dlen - i - 1]; /* make it little endian */
/* using host private key, decrypt the message */
if(CryptDecrypt(hRsaKey, 0, TRUE, 0, buf, &dlen) == FALSE){
perror("Error decrypting using RSA key!");
return GetLastError();
}
for(i = 0; i < (int)dlen; i++)
ptext[i] = buf[dlen - i - 1]; /* make it big endian */
CryptDestroyKey(hRsaKey);
free(buf);
free(pBlob);
free(pKeyin);
return dlen;
}
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]