首页 新闻 会员 周边

ios openssl rsa 加密问题

0
悬赏园豆:100 [已解决问题] 解决于 2014-05-22 17:37

本人使用java做后台,后台使用同一公钥文件(格式为ANS.1 DER编码方式 长度为2048模长 ),加密111111(NO_PADDING)字符串得到结果 A55F50..... 开头的16进制编码,但是在ios平台使用openssl和同一公钥文件加密111111始终得不到A55F50开头的结果,代码如下,请大神帮忙看看....

    #define MODULUS "CF4D10C2C011FCF1EE8F660C9B8AD7E7C8BAAB285C8168F2B355145CCFEAE4E555AC1C4926B00FFF23EC49800B159040F05BA1CC25F4D997311048292904B4015E5A419C0CFE21CC08B144575CC65BD05D5B36EECC190592BD66DACA68B49A3B0D2B1ACE4D26F50339DB834004FAABF399BD66296CA85C8F3E840E1864036A2CDDBDC5188CCF6C23928AA699C3564DB1F83561501A2C8033A34516161DF27B9C8357041291B39203C53E87027F2024A07F3DEBD41FB286CEB4824659347BF2863A6688497E56BFE4B417992F026719D2A199EC6481983636D10FBF74B8011EE5A8D27EAFE7A8E7B33FFED35167783B5753C74C2EBA7C36D134F1090EACEBC225"
    
    #define PUBLIC_EXPONENT 65537
    
    int ret, flen;
    BIGNUM *bnn, *bne,*bnd;
    
    bnn = BN_new();
    bne = BN_new();
    //bnd = BN_new();
     
    
    BN_hex2bn(&bnn, MODULUS);
    BN_set_word(bne, PUBLIC_EXPONENT);
    //BN_hex2bn(&bnd, MODULUS);
    
    RSA *r = RSA_new();
    //RSA* r = RSA_generate_key( 2048 ,RSA_F4,0,0);
    
    
    r->e = bne;
    r->n = bnn;
    //r->d = bnd;
    
    RSA_print_fp(stdout, r, 5);
    
    flen = RSA_size(r);// - 11;
    
    /*out = (char *)malloc(flen);
     bzero(out, flen);*/
    //memset(out, 0, flen);
    
    char *sp = (char *)malloc(flen);
    bzero(sp, flen);
    //memset(sp, 0, flen);
    
    char *message = "111111";
    
    BIGNUM *rs;
    
    rs = BN_new();
    
    ret = RSA_public_encrypt(flen, (unsigned char *)message  , (unsigned char *)sp, r, RSA_NO_PADDING);
    
    if (ret > 0)
    {
        //BN_bin2bn((unsigned char *)sp, flen, rs);
        //NSLog(@"Encrypt OK, sp=%s",BN_bn2hex(rs));//转为16进制
        unsigned  char *tmpData;
        
        tmpData=(unsigned char *)sp;
        
        for  (int i=0; i<ret; i++){
            printf("%02X", *tmpData);
            tmpData++;
        }
        
        //BN_bin2bn((unsigned char *)sp, flen, rs);
        //NSLog(@"Encrypt OK, sp=%s",BN_bn2hex(rs));//转为16进制
    }
 
    RSA_free(r);
TuWei的主页 TuWei | 初学一级 | 园豆:129
提问于:2014-02-17 20:32
< >
分享
最佳答案
0

验证的方式是使用配对的私钥能够解密,解密后的原文一致就正确,跟密文是否一致无关。

收获园豆:100
Launcher | 高人七级 |园豆:45045 | 2014-02-18 09:10

我的加密方式是NO_padding ,而且我使用rsa测试软件和我java加密的结果一样,你还能说跟密文是否一致无关吗

 

TuWei | 园豆:129 (初学一级) | 2014-02-18 09:22

@TuWei: 在你的代码中:BN_num_bytes(r->n) 等于多少? flen 又等于多少?

Launcher | 园豆:45045 (高人七级) | 2014-02-18 11:09

@Launcher: 两个都是256

TuWei | 园豆:129 (初学一级) | 2014-02-18 11:14

@TuWei: 不用你算了,我给你计算了,是 256,你的代码有 BUG(缓冲区溢出),你为了保证 256 字节长度,你的 RSA_public_encrypt 的第一个参数传入了 256,但是,你的第二个参数 message 只有 6 ,那么在使用 RSA_NO_PADDING 时,RSA_padding_add_none 方法会执行 memcpy(to,message,(unsigned int)flen) 语句,因为你的 message 只有前 6 个字节是相同的,后面的内容属于未正确分配的内存,其内容不定,这是你代码的 BUG(缓冲区溢出)。你应该将 message 扩展到 256,6 字节以后的内容用 0 或者别的值来填充。

Launcher | 园豆:45045 (高人七级) | 2014-02-18 11:17

@Launcher: 我应该将 char *message = "111111"; 改为char message[256] = "111111"; ?

我改了后貌似结果还是不对。

TuWei | 园豆:129 (初学一级) | 2014-02-18 11:25

@TuWei: 我这样跟你说吧,你在 openssl 传入的 256 字节内容,必须同你的其它平台使用 RSA 加密时使用的 256 字节内容一致。

Launcher | 园豆:45045 (高人七级) | 2014-02-18 11:28

@Launcher: 关键我对c是真的不熟,java中我就是直接加密111111,c这里真不知怎么处理啊

TuWei | 园豆:129 (初学一级) | 2014-02-18 11:33

@TuWei: java 中采用 no padding 后,如果你也是传入的 6 个字节的 "111111",那么根据你使用的 key 为 2048,那么 java 内部应该也有机制将你的 6 个字节补足 256 字节,最有可能的填充方式就是,在 6 字节后全部填写为 0 。

另外,我不知道你的 java 代码怎么写的,因为 java 中的 string 是 unicode 编码,要加密,首先需要将 string 转换成 byte 数组,如果采用 unicode 编码,那么转换出的就是 12 个字节,而不是 6 个字节(在 C 就是 char)。这样,不管填充的值是否相同,至少你前 12 个字节的内容就是不一样的。

从代码中你也看到了,设置 NO Padding 不代表不 Padding,这个动作只是改由你自己来完成,java 中可能做了封装,让你省去这一步。

Launcher | 园豆:45045 (高人七级) | 2014-02-18 11:42

@Launcher: java中是将字符串转为了byte数组然后加密的

TuWei | 园豆:129 (初学一级) | 2014-02-18 11:59

@Launcher: 大神求救啊,还是搞不定啊

TuWei | 园豆:129 (初学一级) | 2014-02-18 12:30

@Launcher: 

char message[256] = {'1','1','1','1','1','1',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

得到的还是"111111"加密的结果

TuWei | 园豆:129 (初学一级) | 2014-02-18 12:38

@TuWei: 你在 openssl 中传入相同的 message,两次加密的结果是不是一样的?

Launcher | 园豆:45045 (高人七级) | 2014-02-18 13:05

@TuWei: 你在 java 中转换出来的 byte 数组长度是多少?内容是什么?

Launcher | 园豆:45045 (高人七级) | 2014-02-18 13:06

@Launcher: 

     byte[] bytes = "111111".getBytes();
        for(int i = 0; i < bytes.length;i++){
            System.out.println(bytes[i]);
        }

结果:

49

49

49

49

49

49

TuWei | 园豆:129 (初学一级) | 2014-02-18 13:31

@TuWei: byte[] bytes = "111111".getBytes(); 你这里这个 bytes 也得是 256 大小,其余的用 0 填充。

Launcher | 园豆:45045 (高人七级) | 2014-02-18 13:33

@Launcher: 这个不清楚,反正我这样加密

byte[] enBytes = cipher.doFinal("111111".getBytes());

出来的结果和网上下载的rsa计算工具得到的结果一样,而且送给加密机解密也正确,就是说java这端加密是没有问题的

TuWei | 园豆:129 (初学一级) | 2014-02-18 13:38

@Launcher: 下面是doFinal方法的解释 

      Encrypts or decrypts data in a single-part operation, or finishes a multiple-part operation. The data is encrypted or decrypted, depending on how this cipher was initialized.

The bytes in the input buffer, and any input bytes that may have been buffered during a previous update operation, are processed, with padding (if requested) being applied. If an AEAD mode such as GCM/CCM is being used, the authentication tag is appended in the case of encryption, or verified in the case of decryption. The result is stored in a new buffer.

Upon finishing, this method resets this cipher object to the state it was in when previously initialized via a call to init. That is, the object is reset and available to encrypt or decrypt (depending on the operation mode that was specified in the call to init) more data.

Note: if any exception is thrown, this cipher object may need to be reset before it can be used again.

TuWei | 园豆:129 (初学一级) | 2014-02-18 13:43

@TuWei:RSA 在不采用 Padding 的模式下,2048 位,每次输入的明文必须是 2048 / 8 = 256 字节。某些框架在用户输入少于 256 字节时,可能采用帮助用户自动补足 256 字节的“黑箱操作”,而使用什么值来补足,由框架实现,我不知道。但是,openssl 不会这么做,它要求用户必须传入 256 字节的完整数据。

另外,.Net 中的 RSA 处于安全考虑屏蔽了 No Padding 模式,从这里也可以看到,具体实现方式依各框架而定。

 

经过在 openssl 1.0.1e 上的测试,上述表述正确。因此,如果你发现了差异,那么你需要从上述表述中找到限定条件(2048位,RSA_NO_PADDING,256 字节明文,PublicKey),然后比较你在不同框架下的这些限定条件是否一致。

 

最后,祝你好运。

Launcher | 园豆:45045 (高人七级) | 2014-02-18 14:24

@Launcher: 好吧,谢谢了

TuWei | 园豆:129 (初学一级) | 2014-02-18 14:28
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册