1. 程式人生 > >OpenSSL中AES加密的用法

OpenSSL中AES加密的用法

使用API的時候,需要特別小心資料長度,我在初次使用的時候簡直被弄的暈頭轉向,遂作此文留個備忘。一般沒有指定長度的引數,預設都是16(AES_BLOCK_SIZE)個位元組。輸出資料的長度一般都是16位元組的倍數,否則會出現陣列越界訪問。
以下API中,encrypt表示加密,decrypt表示解密。

1.生成加密/解密的Key

int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
                        AES_KEY *key);
int AES_set_decrypt_key(const
unsigned char *userKey, const int bits, AES_KEY *key);

引數說明:

引數名稱 描述
userKey 使用者指定的密碼。注意:只能是16、24、32位元組。如果密碼字串長度不夠,可以在字串末尾追加一些特定的字元,或者重複密碼字串,直到滿足最少的長度。
bits 密碼位數。即userKey的長度 * 8,只能是128、192、256位。
key 向外輸出引數。

如果函式呼叫成功,返回0,否則是負數。

2.使用AES加密/解密

void
AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key); void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);

引數說明:

引數名稱 描述
in 輸入資料。必須是16位元組。
out 輸出資料。必須是16位元組。
key 使用AES_set_encrypt/decrypt_key生成的Key。

AES_encrypt/AES_decrypt一次只處理16個位元組。如果輸入資料較長,你需要使用迴圈語句,每16個位元組處理一次,直到所有資料處理完畢。如果資料不足16位元組,可以用0填充至16位元組。

3.使用AES CBC加密/解密

void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
                     size_t length, const AES_KEY *key,
                     unsigned char *ivec, const int enc);

引數說明:

引數名稱 描述
in 輸入資料。長度任意。
out 輸出資料。能夠容納下輸入資料,且長度必須是16位元組的倍數。
length 輸入資料的實際長度。
key 使用AES_set_encrypt/decrypt_key生成的Key。
ivec 可讀寫的一塊記憶體。長度必須是16位元組。
enc 是否是加密操作。AES_ENCRYPT表示加密,AES_DECRYPT表示解密。

這個函式比AES_encrypt多了一個ivec引數,ivec的內容可以任意指定,但是加密和解密操作必須使用同樣的資料。在AES_cbc_encrypt底層,實際上是每16個位元組做一次處理,先和ivec做異或運算,然後呼叫AES_encrypt函式進行加密。
AES_cbc_encrypt在加密的過程中會修改ivec的內容,因此ivec引數不能是一個常量,而且不能在傳遞給加密函式後再立馬傳遞給解密函式,必須重新賦值之後再傳遞給解密函式。

關於輸出資料的長度
輸出資料緩衝區的長度必須是16位元組的倍數,加密完成後,比輸入長度多出來的輸出資料是不可以丟棄的。因此,存檔的時候,需要記錄原始資料的長度

關於輸入資料的長度不必是16位元組的倍數(做個備忘):
下面是AES_cbc_encrypt函式的底層實現程式碼

    ... 
    //處理16位元組倍數的資料
    while (len >= 16) {
            for (n = 0; n < 16; ++n)
                out[n] = in[n] ^ iv[n];
            (*block) (out, out, key); //呼叫AES_encrypt處理資料
            iv = out;
            len -= 16;
            in += 16;
            out += 16;
        }
    //當資料小於16位元組的時候,進入下面的迴圈
    while (len) { 
        for (n = 0; n < 16 && n < len; ++n)
            out[n] = in[n] ^ iv[n];
        for (; n < 16; ++n)
            out[n] = iv[n]; //使用ivec補齊不足16位元組的部分
        (*block) (out, out, key); //呼叫AES_encrypt處理資料
        iv = out;
        if (len <= 16)
            break;
        len -= 16;
        in += 16;
        out += 16;
    }

4.結尾

其他加密函式我還沒有用過,在此就不繼續列舉了,但是引數跟上面幾個相似,弄明白上面的就不成問題。