C加密逻辑与java不匹配

C加密逻辑与java不匹配,c,encryption,openssl,cryptography,evp-cipher,C,Encryption,Openssl,Cryptography,Evp Cipher,我正在为下面的java代码寻找等效的C代码。 我正在尝试用java和C编写两个应用程序。 Java应用程序使用下面的逻辑对“字符串”进行加密/解密,当使用下面的Java方法时,它正在工作 公共类AEScrypt{ 公共静态字符串encryptString(字符串strotEncrypt,字符串secret,字符串salt,字节[]iv){ 试一试{ IvParameterSpec ivspec=新的IvParameterSpec(iv); SecretKeyFactory keyFactory=

我正在为下面的java代码寻找等效的C代码。 我正在尝试用java和C编写两个应用程序。 Java应用程序使用下面的逻辑对“字符串”进行加密/解密,当使用下面的Java方法时,它正在工作

公共类AEScrypt{
公共静态字符串encryptString(字符串strotEncrypt,字符串secret,字符串salt,字节[]iv){
试一试{
IvParameterSpec ivspec=新的IvParameterSpec(iv);
SecretKeyFactory keyFactory=SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);
KeySpec KeySpec=new-PBEKeySpec(secret.tocharray(),salt.getBytes(),65536256);
SecretKey secretKeySpec=keyFactory.generateScret(keySpec);
SecretKeySpec secretKey=newsecretkeyspec(SecretKeySpec.getEncoded(),“AES”);
Cipher Cipher=Cipher.getInstance(“AES/CBC/NoPadding”);
cipher.init(cipher.ENCRYPT_模式,secretKey,ivspec);
整数长度=0;
if(strotencrypt.length()16&&strotencrypt.length()
对于加密:

  • 我们使用HMAC-sha256生成“密钥”,该密钥包含“salt”、“password”
  • 不,您正在将PBKDF2与HMAC-SHA256一起使用。这与普通HMAC-SHA256完全不同。但是,您标识的OpenSSL函数与此匹配,前提是您为其提供了正确的参数。这也适用于解密步骤1

  • 填充输入数据
  • 排序。这种填充仅适用于最多16个字符的输入数据,所有字符都是ASCII(因为您将其编码为UTF-8,任何非ASCII字符都会产生多个字节,使编码值成为非法长度)。大多数较长的值将失败,尽管少数值会因运气不佳而成功。即使对于“成功”的值,也会更改一些值;这被视为不好的做法,从1980年开始,基本上所有设计完善的加密方案都旨在保存所有数据。特别是非常常见的PKCS5(出于技术原因,有时称为PKCS7或PKCS5/PKCS7)标准填充可以正确保存所有数据,并且已经在Java和OpenSSL以及几乎所有其他体面的加密库和设备中实现,是更好的选择,也更简单

    在填充固定的情况下,Java端可以处理非ASCII数据,但前提是对要加密的明文进行编码,并在解密后对明文进行适当解码。加密时有
    .getBytes(StandardCharsets.UTF_8)
    ,但需要将其与
    新字符串(cipher.doFinal(…),StandardCharsets.UTF_8)匹配
    在解密时,否则它可能工作,也可能不工作,这取决于运行它所使用的平台和环境

    C端可能更难。OpenSSL基于在1995年和1999年版本C开始处理非英语字符之前开始的老式C代码,它只理解字节,可以是单字节又称为“窄”字符。或者,您必须用调用代码包装它,在多字节编码(如UTF-8)中处理“宽”字符(并使用字节调用OpenSSL部分),或者您必须在程序外部通过控制环境(如终端或模拟器)或文件来执行此操作。您的问题甚至没有提供任何关于这些内容的提示,因此不可能提出任何建议

    因为您将“secret”(password)、salt和IV视为
    String
    s,所以对它们的考虑是相同的,只是它们可能来自不同的来源IV和salt被设计为字节序列,特别是将IV限制为ASCII甚至UTF-8编码可能会降低一些安全性,但由于其主题是编程,而不是安全性,我不会继续讨论。在PKCS5中的实际PBKDF2密码也是八位字节(Java字节),但它“建议”文本(字符)被编码为ASCII或UTF-8,Java在
    PBEKeySpec
    中采用
    char[]
    并编码为UTF-8,因此对于非ASCII,OpenSSL调用方或环境需要与之匹配

    考虑到这些限制:所有值仅为ASCII,数据不超过16个字符=字节,IV正好为16,以下C代码匹配并且可以与Java进行互操作。错误处理非常简单,我在单个函数中加密和解密;您希望能够将它们分开。(更正)

    /*SO65195128.c 2009年12月20日,11*/
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    void err(int n,const char*s){printf(“%s:%d\n”,s,n);err_print_errors_fp(stdout);退出(1);}
    int main(int argc,字符**argv){
    如果(argc!=5 | strlen(argv[3])!=16 | strlen(argv[4])>16{printf(“坏args\n”);退出(1)}
    常量字符*pw=argv[1],*salt=argv[2],*iv=argv[3],*org=argv[4];
    无符号字符键[32]、pad[16]、enc[16]、b64[25]、unb[16]、dec[16];
    内部rc、len、temp、i、j;
    SSL_库_init();
    /*两者皆有*/
    rc=PKCS5_PBKDF2_HMAC(pw,strlen(pw),(未签名字符*)salt,strlen(salt),65536,EVP_sha256(),32,key);
    如果(rc!=1)错误(rc,“PBKDF2”);
    EVP_CIPHER_CTX*CTX=EVP_CIPHER_CTX_new();
    /*用于加密*/
    len=strlen(org);memset(pad',,16 len);memcpy(pad+16 len,org,len);
    rc=EVP_EncryptInit(ctx,EVP_aes_256_cbc(),key,(unsigned char*)iv);
    如果(rc!=1)err(rc,“EncryptInit”);
    rc=EVP\u密码\u CTX\u集合\u填充(CTX,0);
    如果(rc!=1)错误(rc,“设置填充”);
    rc=执行副总裁加密更新(ctx、enc和len、pad、16);
    如果(rc!=1 | | len!=16)错误(rc,“加密更新”);
    rc=执行副总裁(ctx、enc+len和temp);
    如果(rc!=1 | | temp!=0)错误(rc,“EncryptFinal”);
    rc=EVP_编码块(b64,enc,16);
    
    如果(rc)首先,将问题隔离到一个步骤。例如,使用Java和C测试base64编码。如果得到不同的结果,则调试base64编码。如果得到相同的结果,则测试AES加密。完成isol后
    int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
                           const unsigned char *salt, int saltlen, int iter,
                           const EVP_MD *digest,
                           int keylen, unsigned char *out);
    
    /* SO65195128.c 20dec09,11 */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <openssl/evp.h>
    #include <openssl/err.h>
    #include <openssl/ssl.h>
    
    void err (int n, const char * s){ printf("%s:%d\n", s, n); ERR_print_errors_fp(stdout); exit(1); }
    
    int main (int argc, char **argv){
        if( argc != 5 || strlen(argv[3]) != 16 || strlen(argv[4]) > 16 ){ printf("bad args\n"); exit(1); }
        const char * pw = argv[1], * salt = argv[2], * iv = argv[3], * org = argv[4];
        unsigned char key [32], pad [16], enc [16], b64 [25], unb [16], dec [16];
        int rc, len, temp, i, j;
        SSL_library_init();
    
        /* for both */
        rc = PKCS5_PBKDF2_HMAC (pw, strlen(pw), (unsigned char*)salt, strlen(salt), 65536, EVP_sha256(), 32, key);
        if( rc != 1 ) err(rc,"PBKDF2");
        EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    
        /* for encrypt */
        len = strlen(org); memset(pad, ' ', 16-len); memcpy (pad+16-len, org, len);
        rc = EVP_EncryptInit (ctx, EVP_aes_256_cbc(), key, (unsigned char*)iv);
        if( rc != 1 ) err(rc,"EncryptInit");
        rc = EVP_CIPHER_CTX_set_padding(ctx,0);
        if( rc != 1 ) err(rc,"set_padding");
        rc = EVP_EncryptUpdate (ctx, enc, &len, pad, 16);
        if( rc != 1 || len != 16 ) err(rc,"EncryptUpdate");
        rc = EVP_EncryptFinal (ctx, enc+len, &temp); 
        if( rc != 1 || temp != 0 ) err(rc,"EncryptFinal");
        rc = EVP_EncodeBlock(b64, enc, 16);
        if( rc <= 0 ) err(rc,"EncodeBlock");
    
        printf ("%.*s\n", rc, b64);
    
        /* for decrypt */
        rc = EVP_DecodeBlock(unb, b64, /*len*/rc)-(b64[rc-1]=='=')-(b64[rc-2]=='=');
        /* this is a hack, should go for DecodeInit,Update,Final */
        if( rc != 16 ) err(rc,"DecodeBlock");
        rc = EVP_DecryptInit (ctx, EVP_aes_256_cbc(), key, (unsigned char*)iv);
        if( rc != 1 ) err(rc,"DecryptInit");
        rc = EVP_CIPHER_CTX_set_padding(ctx,0);
        if( rc != 1 ) err(rc,"set_padding");
        rc = EVP_DecryptUpdate (ctx, dec, &len, unb, 16);
        if( rc != 1 || len != 16 ) err(rc,"DecryptUpdate");
        rc = EVP_DecryptFinal (ctx, dec+len, &temp); 
        if( rc != 1 || temp != 0 ) err(rc,"DecryptFinal");
        i=0; while(i<16&&dec[i]<=' ') i++; j=16; while(j>0&&dec[j-1]<=' ') j--;
    
        printf ("%.*s\n", j-i, dec+i);
        /* note this is NOT a C string -- needs to be copied and NUL added for that */
    
        return 0;
    }