首页  编辑  

Lockbox和Open SSL兼容性

Tags: /超级猛料/Open Source.开源代码/   Date Created:

Open SSL 和Lockbox的兼容性问题

Lockbox是Toubo Power中的加密SDK,封装了常见的加密算法,如RSA,3DES(Triple-DES),DES,MD5等等,在Delphi/C++ Builder中使用非常简单方便。Open SSL是一个开源的C/C++ 加密库,同样实现了RSA,3DES,MD5等加密算法,在Linux等C/C++环境下使用也非常方便。但对于使用Open SSL加密的数据,直接拿到Lockbox下是无法解密的,因为两者的兼容性存在一些问题,如RSA KEY文件存储两者是不一致的,导致RSA等加密算法实现差异,无法互通。

对于RSA等公钥加密算法,涉及到KEY文件的定义和输出,Open SSL和Lockbox是不一致的。高精度整数输出时LockBox是逆序输出高位在后,而OpenSSL是顺序序输出高位在前。

还有LockBox是以Byte形式进行操作,OpenSSL是以Int(可能是64位、32位、16位、8位根据宏定义进行选择)形式进行操作。

因此,针对以上情况,利用Lockbox生成密钥对之后,Open SSL在读取Lockbox的密钥文件的时候,要进行特殊处理:

       //取得lockbox key,直接从文件中读取到内存块

       key=d2i_RSAPublicKey_bio(in_,NULL);

       //转化成openssl认识的key

       memset(p,0,sizeof(p)-1);

       num=BN_num_bytes(key->n);

       memcpy(p,key->n->d,num);

       tokey->n=BN_bin2bn(p,num,tokey->n);

       //这里先取得明文加密长度

       plainbytes=num-cRSAMinPadBytes;

       //转化成openssl认识的key

   memset(p,0,sizeof(p)-1);

       num=BN_num_bytes(key->e);

       memcpy(p,key->e->d,num);

       tokey->e=BN_bin2bn(p,num,tokey->e);

完整的代码如下:

//2.RSA,调用代码如下:

void Encrypt()

{

 static int BUFFER_SIZE=256;

       RSA *key,*tokey;

       char *infile=NULL,*fromfile,*tofile=NULL;

       BIO *in_=NULL,*fromio,*toio=NULL;

       int modulus=0;

       long num,i,j;

       int plen,outlength;

       unsigned char *ptext,*p,*p1;

       BUF_MEM * buf,*outbuf;

       BIGNUM ff,ret,ee,nn;

       //rsa最新补齐字节

       static int cRSAMinPadBytes = 11;

       //加密块明文最大长度

       int plainbytes;

       //加密块明文 实际长度

       int actualbytes;

       //加密块数

       int blockcount;

       //lockbox产生的公钥

       infile= "D:\\openssl-0.9.6m\\test\\PublicKey.dat";  // PublicKey由LockboxGenerateKeyPaire并SaveToFile生成的。

       //明文文件

       fromfile= "D:\\openssl-0.9.6m\\test\\ctext.dat";

       //保存密文目的文件

       tofile= "D:\\openssl-0.9.6m\\test\\ctext.dat.enc";

       in_=BIO_new(BIO_s_file());

       fromio=BIO_new(BIO_s_file());

       toio=BIO_new(BIO_s_file());

       BN_CTX *ctx=NULL;

       

       ptext=(unsigned char *)OPENSSL_malloc(BUFFER_SIZE);

       p    =(unsigned char *)OPENSSL_malloc(BUFFER_SIZE);

       BN_init(&ff);

       BN_init(&ret);

       BN_init(&ee);

       BN_init(&nn);

       ctx=BN_CTX_new();

       if (BIO_read_filename(in_,infile) <= 0)

       {

               //perror(infile);

               return;

       }

       CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);

       //取得lockbox key

       key=d2i_RSAPublicKey_bio(in_,NULL);

       

       tokey = RSA_new();

       //转化成openssl认识的key

       memset(p,0,sizeof(p)-1);

       num=BN_num_bytes(key->n);

       memcpy(p,key->n->d,num);

       tokey->n=BN_bin2bn(p,num,tokey->n);

       //这里先取得明文加密长度

       plainbytes=num-cRSAMinPadBytes;

       //转化成openssl认识的key

   memset(p,0,sizeof(p)-1);

       num=BN_num_bytes(key->e);

       memcpy(p,key->e->d,num);

       tokey->e=BN_bin2bn(p,num,tokey->e);

       //读取明文

       if(in_ != NULL) BIO_free(in_);

       if (BIO_read_filename(fromio,fromfile) <= 0)

       {

               return;

       }

       plen=0;

       if ((buf=BUF_MEM_new()) == NULL) return;

       

       for (;;)

       {

               if (!BUF_MEM_grow(buf,(int)plen+BUFSIZ)) return;

               i=BIO_read(fromio,&(buf->data[plen]),BUFSIZ);

               if (i <= 0) break;

               plen+=i;

       }

       blockcount = plen / plainbytes;

       if(plen% plainbytes> 0)blockcount++;

       

       //开始加密

       //loop begin

       //for 0 to count -1 block

       //every block content less than

       

       outlength= 0;

       if ((outbuf=BUF_MEM_new()) == NULL) return;

       for(i=0;i<blockcount;i++){

               p1=(unsigned char *)&(buf->data[i*plainbytes]);

               actualbytes=plainbytes;

               if(i==blockcount-1) actualbytes=plen - (plainbytes * i);

               memset(p,0,sizeof(p)-1);

               //字节倒序

               for(j=0;j<actualbytes;j++){

                       p[j]=p1[actualbytes-1-j];

               }        

               num = BN_num_bytes(tokey->n);

               //补齐按PKCS1

               RSA_padding_add_PKCS1_type_2(ptext,num,p,actualbytes);

               /* make data into a big number */

               BN_bin2bn(ptext,num,&ff);

               //加密

               num = BN_mod_exp(&ret,&ff,tokey->e,tokey->n,ctx);

               num=BN_num_bytes(&ret);

               BN_bn2bin(&ret,p);

               memset(ptext,0,sizeof(ptext)-1);

               //取回字节倒序

               for(j=0;j<num;j++){

                       ptext[j]=p[num-1-j];

               }

               

               if (!BUF_MEM_grow(outbuf,(int)outlength+num)) return;

               memcpy(&(outbuf->data[outlength]),ptext,num);

       outlength=outlength+num;

               //loop end

       }

       //写流

       BIO_write_filename(toio,tofile);

       BIO_write(toio,outbuf->data,outlength);

       if(toio != NULL) BIO_free(toio);

       if(buf != NULL) BUF_MEM_free(buf);

       if (ctx != NULL) BN_CTX_free(ctx);

       BN_clear_free(&ff);

       BN_clear_free(&ret);

       BN_clear_free(&ee);

       BN_clear_free(&nn);

       if (p != NULL)

       {

               OPENSSL_cleanse(p,BUFFER_SIZE);

               OPENSSL_free(p);

       }

       if (ptext != NULL)

       {

               OPENSSL_cleanse(ptext,BUFFER_SIZE);

               OPENSSL_free(ptext);

       }

       return;        

       

}

//TripleDES,调用代码如下:

// 利用下面的方式加密的数据,Lockbox可以直接解密

//ecb_out:返回加密流

unsigned char * ecb_out=des_ede3_ecb_encrypt(ecb_in,f_len,&len,ks,ks2,ks,DES_ENCRYPT);

/*

input:待加密数据流

length:待加密数据流长度

count :加密后长度

ks1,ks2,ks3:密钥

enc:TRUE为加密,FALSE为解密

返回:加密后数据流

*/

unsigned char * des_ede3_ecb_encrypt(const unsigned char *input,

            long length,long * count, des_key_schedule ks1, des_key_schedule ks2,

            des_key_schedule ks3, int enc)

       {

       //register DES_LONG tin0,tin1;

       register unsigned char *in;

       register unsigned char *out;

       register long i,blocks;

       unsigned char * pin,*pout;

       int iLen;

       DES_LONG tin[2];

       

       if (enc)

               {

               iLen = (length % 8)==0?8:length % 8;

               in = (unsigned char *)malloc(length+(8 -iLen));

               pin=in;

               out= (unsigned char *)malloc(length+(8 -iLen));

               pout=out;

               memcpy((void *)in,input,length);

               

               for(i=length;i<length + (8-iLen);i++){

                       in[i] = iLen;

               }

           blocks=(length+(8-iLen))/8;

               for (i=0;i<blocks; i++)

                       {

                       c2l(in,tin[0]);

                       c2l(in,tin[1]);

                       des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);

                       l2c(tin[0],out);

                       l2c(tin[1],out);

                       }

               *count=length + (8-iLen);

           free(pin);

               return pout;

               }

       else

               {

               in=(unsigned char *)input;

               out= (unsigned char *)malloc(length);

               pout=out;

               blocks=length/8;

               for (i=0;i<blocks; i++)

                       {

                       c2l(in,tin[0]);

                       c2l(in,tin[1]);

                       des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);

                       l2c(tin[0],out);

                       l2c(tin[1],out);

                       }

               iLen=pout[length-1];

               iLen=length -(8-iLen);

               *count=iLen;

               return pout;

               }

       }

Open SSL 和 Lockbox 加密之间区别

描述        

OpenSSL 是目前用途非常广的一个加密解密库 ,LockBox 是 Delphi 实现的一个加密解密库,当用两者其中一个进行加密,另外一个解密时,往往是解不出来,这就非常令人困惑:既然算法相同,只是实现不一样,应该是没有问题才对?!其实,问题出在 RFC 文档没有规定到的一些细节上,比如:当用 DES 加密时,如果待加密字节长度不够 8 的倍数时该怎么补齐?

代码示例

Triple DES 加密解密

DES 都是按照 8 字节进行加密操作的 ,Triple DES 也是一样 , 只不过 DES 是用一个 Key 进行加密解密 , Triple DES 是用 3 个 Key 进行。 OpenSSL 和 LockBox 两者的算法是一致的,差别在于两者在加密字节尾部的操作, OpenSSL 的明文有多少个字节,加密出来的密文就有多少个字节。 LockBox 处理是当明文不是 8 的倍数就补齐够 8 的倍数,并且最后一个字节是 最后 8 个加密字节 有几个是有效的。所以, OpenSSL 要做些改动,代码如下:

1 、         OpenSSL 加密 :

Ret    =  Gen2RandomKeys(&k1, &k2, &ks1, &ks2);

ecb_out =  des_ede3_ecb_encrypt(ecb_in,f_len,&len,ks1,ks2,ks1, DES_ENCRYPT);

// 这两个方法 OpenSSL 里面没有,要自己添加,代码如下:

/* 随机产生 Key 的方法:

k1,k2 是 key 的字节表示,用这两个连起来给 Lockbox 进行解密

ks1,ks2 是 OpenSSL 用来加密解密的分别对等 k1,k2 的对象

*/

int Gen2RandomKeys(des_cblock *k1, des_cblock *k2, des_key_schedule *ks1, des_key_schedule *ks2)

{

       int j;

       char str[64];

       

       printf("Generate random keys.\n");

       srand(time(NULL));

       for(j = 0; j < 63; j++){

               str[j] = rand() * 255;

               printf("%d ", str[j]);

       }

       str[63] = '\0';

       printf("\n");

       

       des_string_to_2keys(str, k1, k2);

       if ((j = des_set_key_checked(k1, *ks1)) != 0){

               printf("Key error %d\n", j);

               return 0;

       }

       

       if ((j = des_set_key_checked(k2, *ks2)) != 0){

               printf("Key2 error %d\n", j);

               return 0;

       }

       

       return 1;

}

/*

加密解密方法:

input: 待加密数据流

length :待加密数据流长度

count : 加密后长度

ks1,ks2,ks3: 密钥

enc:TRUE 为加密 ,FALSE 为解密

返回:加密后数据流

*/

unsigned char * des_ede3_ecb_encrypt(const unsigned char *input,

            long length,long * count, des_key_schedule ks1, des_key_schedule ks2,

            des_key_schedule ks3, int enc)

       {

       //register DES_LONG tin0,tin1;

       register unsigned char *in;

       register unsigned char *out;

       register long i,blocks;

       unsigned char * pin,*pout;

       int iLen;

       DES_LONG tin[2];

       

       if (enc)

               {

               iLen = (length % 8)==0?8:length % 8;

               in = (unsigned char *)malloc(length+(8 -iLen));

               pin=in;

               out= (unsigned char *)malloc(length+(8 -iLen));

               pout=out;

               memcpy((void *)in,input,length);

               

               for(i=length;i<length + (8-iLen);i++){

                       in[i] = iLen;

               }

           blocks=(length+(8-iLen))/8;

               for (i=0;i<blocks; i++)

                       {

                       c2l(in,tin[0]);

                       c2l(in,tin[1]);

                       des_encrypt3((DES_LONG *)tin,ks1,ks2,ks3);

                       l2c(tin[0],out);

                       l2c(tin[1],out);

                       }

               *count=length + (8-iLen);

           free(pin);

               return pout;

               }

       else

               {

               in=(unsigned char *)input;

               out= (unsigned char *)malloc(length);

               pout=out;

               blocks=length/8;

               for (i=0;i<blocks; i++)

                       {

                       c2l(in,tin[0]);

                       c2l(in,tin[1]);

                       des_decrypt3((DES_LONG *)tin,ks1,ks2,ks3);

                       l2c(tin[0],out);

                       l2c(tin[1],out);

                       }

               iLen=pout[length-1];

               iLen=length -(8-iLen);

               *count=iLen;

               return pout;

               }

       }

2 、         LockBox 解密:

// TripleDESEncryptStream 定义:

// InStream: 待操作流,密文或明文

// OutStream :结果流 : 明文或密文

// Key:Key ,长度只有 128 的

// Encrypt:True 为加密, False 为解密

procedure TripleDESEncryptStream(InStream, OutStream : TStream;

           const Key : TKey128; Encrypt : Boolean);

RSA 加密解密

RSA 加密解密 OpenSSL 和 LockBox 的差异主要在于 Key 的表示方法、加密块增加 padding 位置、明文密文的字节序上。代码示例如下:

1 、         OpenSSL 加密:

void Encrypt()

{

 static int BUFFER_SIZE=256;

       RSA *key,*tokey;

       char *infile=NULL,*fromfile,*tofile=NULL;

       BIO *in_=NULL,*fromio,*toio=NULL;

       int modulus=0;

       long num,i,j;

       int plen,outlength;

       unsigned char *ptext,*p,*p1;

       BUF_MEM * buf,*outbuf;

       BIGNUM ff,ret,ee,nn;

       //rsa 最新补齐字节

       static int cRSAMinPadBytes = 11;

       // 加密块明文最大长度

       int plainbytes;

       // 加密块明文 实际长度

       int actualbytes;

       // 加密块数

       int blockcount;

       //lockbox 产生的公钥 , 格式 ASN.1

       infile= "D:\\openssl-0.9.6m\\test\\PublicKey.dat";

       // 明文文件

       fromfile= "D:\\openssl-0.9.6m\\test\\ctext.dat";

       // 保存密文目的文件

       tofile= "D:\\openssl-0.9.6m\\test\\ctext.dat.enc";

   // 文件 IO

       in_=BIO_new(BIO_s_file());

       fromio=BIO_new(BIO_s_file());

       toio=BIO_new(BIO_s_file());

// 上下文

       BN_CTX *ctx=NULL;

       

       ptext=(unsigned char *)OPENSSL_malloc(BUFFER_SIZE);

       p    =(unsigned char *)OPENSSL_malloc(BUFFER_SIZE);

       BN_init(&ff);

       BN_init(&ret);

       BN_init(&ee);

       BN_init(&nn);

       ctx=BN_CTX_new();

       if (BIO_read_filename(in_,infile) <= 0)

       {

               //perror(infile);

               return;

       }

       // 取得 lockbox key

       key=d2i_RSAPublicKey_bio(in_,NULL);

       

       tokey = RSA_new();

       // 转化成 openssl 认识的 key

       memset(p,0,sizeof(p)-1);

       num=BN_num_bytes(key->n);

       memcpy(p,key->n->d,num);

       tokey->n=BN_bin2bn(p,num,tokey->n);

       // 这里先取得明文加密长度

       plainbytes=num-cRSAMinPadBytes;

       // 转化成 openssl 认识的 key

   memset(p,0,sizeof(p)-1);

       num=BN_num_bytes(key->e);

       memcpy(p,key->e->d,num);

       tokey->e=BN_bin2bn(p,num,tokey->e);

       // 读取明文

       if(in_ != NULL) BIO_free(in_);

       if (BIO_read_filename(fromio,fromfile) <= 0)

       {

               return;

       }

       plen=0;

       if ((buf=BUF_MEM_new()) == NULL) return;

       

       for (;;)

       {

               if (!BUF_MEM_grow(buf,(int)plen+BUFSIZ)) return;

               i=BIO_read(fromio,&(buf->data[plen]),BUFSIZ);

               if (i <= 0) break;

               plen+=i;

       }

       blockcount = plen / plainbytes;

       if(plen% plainbytes> 0)blockcount++;

       

       // 开始加密

       //loop begin

       //for 0 to count -1 block

       //every block content less than

       

       outlength= 0;

       if ((outbuf=BUF_MEM_new()) == NULL) return;

       for(i=0;i<blockcount;i++){

               p1=(unsigned char *)&(buf->data[i*plainbytes]);

               actualbytes=plainbytes;

               if(i==blockcount-1) actualbytes=plen - (plainbytes * i);

               memset(p,0,sizeof(p)-1);

               // 字节倒序

               for(j=0;j<actualbytes;j++){

                       p[j]=p1[actualbytes-1-j];

               }        

               num = BN_num_bytes(tokey->n);

               // 补齐按 PKCS1

               RSA_padding_add_PKCS1_type_2(ptext,num,p,actualbytes);

               /* make data into a big number */

               BN_bin2bn(ptext,num,&ff);

               // 加密

               num = BN_mod_exp(&ret,&ff,tokey->e,tokey->n,ctx);

               num=BN_num_bytes(&ret);

               BN_bn2bin(&ret,p);

               memset(ptext,0,sizeof(ptext)-1);

               // 取回字节倒序

               for(j=0;j<num;j++){

                       ptext[j]=p[num-1-j];

               }

               

               if (!BUF_MEM_grow(outbuf,(int)outlength+num)) return;

               memcpy(&(outbuf->data[outlength]),ptext,num);

       outlength=outlength+num;

               //loop end

       }

       // 写流

       BIO_write_filename(toio,tofile);

       BIO_write(toio,outbuf->data,outlength);

       if(toio != NULL) BIO_free(toio);

       if(buf != NULL) BUF_MEM_free(buf);

       if (ctx != NULL) BN_CTX_free(ctx);

       BN_clear_free(&ff);

       BN_clear_free(&ret);

       BN_clear_free(&ee);

       BN_clear_free(&nn);

       if (p != NULL)

       {

               OPENSSL_cleanse(p,BUFFER_SIZE);

               OPENSSL_free(p);

       }

       if (ptext != NULL)

       {

               OPENSSL_cleanse(ptext,BUFFER_SIZE);

               OPENSSL_free(ptext);

       }

       return;        

       

}

2 、         LockBox 调用示例:

// RSAEncryptStream 定义:

// InStream: 待操作流,密文或明文

// OutStream :结果流 : 明文或密文

// Key:Key ,长度只有 128 的

// Encrypt:True 为加密, False 为解密

RSAEncryptStream(instream, outStream, lbRsaKey, False);