在C中使用OpenSSL API进行加密

时间:2015-05-10 12:56:29

标签: c encryption openssl

它没有重复,因为我没有问如何加密,但我问我的加密有什么问题。不喜欢这个问题你可以自由删除它。我不在乎。

我正在尝试加密一个简单的hello文本文件。

这是我加密数据的代码。

int encrypt(EVP_CIPHER_CTX *ctx, FILE *ifp,FILE *ofp)
{
        int bytes_read, bytes_written, enc_bytes,tlen;
        unsigned char indata[AES_BLOCK_SIZE];
        unsigned char encdata[AES_BLOCK_SIZE];
        unsigned char outdata[AES_BLOCK_SIZE];
        while (1) {
            bytes_read = fread(indata, 1, AES_BLOCK_SIZE, ifp);

            if (EVP_EncryptUpdate (ctx, encdata, &enc_bytes, indata, bytes_read) != 1)
            {   
                    printf ("error in encrypt update\n");
                    return -1; 
            }   
            printf ("INPUT\n");
            print_memory(indata, bytes_read);
            if (EVP_EncryptFinal (ctx, encdata + enc_bytes, &tlen) != 1)
            {   
                    printf ("error in encrypt final\n");
                    return -1; 
            }   

            printf ("OUTPUT\n");
            print_memory(encdata,enc_bytes+tlen);
            bytes_written = fwrite(encdata, 1,enc_bytes + tlen, ofp);
            if (bytes_read < AES_BLOCK_SIZE)
                    break;
    }   

这是key和ivec,我用于初始化

unsigned char ckey[] =  {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF};
unsigned char ivec[] = {0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF};


EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init (&ctx);
EVP_EncryptInit (&ctx, EVP_bf_cbc (), ckey, ivec);

以下是以十六进制表示的输出加密数据24 47 50 58 93 0B 04 9C D5 54 65 93 D1 6B AD 5A

但是当我尝试使用openSSL cmd解码数据时 我收到以下错误

anshul:~/> openssl aes-128-cbc  -d  -in  otext  -K 000102030405060708090A0B0C0D0E0F -iv 000102030405060708090A0B0C0D0E0F -nosalt
bad decrypt
3075450556:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529:

如果我使用错误的ivec或密钥,这是同样的错误。 所以我确实猜测c程序密钥或ivec和openssl cmd密钥或ivek有不同的东西

1 个答案:

答案 0 :(得分:0)

  

我正在尝试加密一个简单的hello文本文件...
  我从http://openssl.org/docs/crypto/EVP_EncryptInit.html#EXAMPLES ...

中获取了代码

以下是来自EVP Authenticated Encryption and Decryption的OpenSSL wiki的示例。它使用GCM模式,因为您经常需要/需要机密性真实性保证,而不仅仅是机密性

OpenSSL例程处理内存中的字节字符串。因此,您必须读取该文件并向OpenSSL函数提供一个字节字符串。

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *aad,
    int aad_len, unsigned char *key, unsigned char *iv,
    unsigned char *ciphertext, unsigned char *tag)
{
    EVP_CIPHER_CTX *ctx;

    int len, ciphertext_len;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

    /* Initialise the encryption operation. */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
        handleErrors();

    /* Set IV length if default 12 bytes (96 bits) is not appropriate */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
        handleErrors();

    /* Initialise key and IV */
    if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();

    /* Provide any AAD data. This can be called zero or more times as
     * required
     */
    if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /* Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     */
    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
        handleErrors();
    ciphertext_len = len;

    /* Finalise the encryption. Normally ciphertext bytes may be written at
     * this stage, but this does not occur in GCM mode
     */
    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
    ciphertext_len += len;

    /* Get the tag */
    if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag))
        handleErrors();

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

解密程序:

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *aad,
    int aad_len, unsigned char *tag, unsigned char *key, unsigned char *iv,
    unsigned char *plaintext)
{
    EVP_CIPHER_CTX *ctx;
    int len, plaintext_len, ret;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();

    /* Initialise the decryption operation. */
    if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
        handleErrors();

    /* Set IV length. Not necessary if this is 12 bytes (96 bits) */
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL))
        handleErrors();

    /* Initialise key and IV */
    if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handleErrors();

    /* Provide any AAD data. This can be called zero or more times as
     * required
     */
    if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len))
        handleErrors();

    /* Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary
     */
    if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
        handleErrors();
    plaintext_len = len;

    /* Set expected tag value. Works in OpenSSL 1.0.1d and later */
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag))
        handleErrors();

    /* Finalise the decryption. A positive return value indicates success,
     * anything else is a failure - the plaintext is not trustworthy.
     */
    ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    if(ret > 0)
    {
        /* Success */
        plaintext_len += len;
        return plaintext_len;
    }
    else
    {
        /* Verify failed */
        return -1;
    }
}
anshul:~/> openssl aes-128-cbc -d -in ...

对于GCM模式,这不起作用。尚未为OpenSSL encryptdecrypt子命令切入GCM。请参阅OpenSSL邮件列表中的AES-GCM failing from Command Line Interface

如果您想知道, 是使用其他模式的有效理由,例如CBC或OFB。使用GCM模式。