對稱加密(或對稱密鑰加密)使用相同的密鑰用於加密和解密:
對稱密鑰加密很有價值,有如下原因:
- 爲這些密碼生成一個祕鑰相對容易。
- 就他們所能提供的保護水平而言,祕鑰往往要小得多。
- 這些算法的處理成本相對較低。
因此,實現對稱加密(特別是使用硬件)可能非常有效,因爲加密和解密不會導致任何顯著的時間延遲。對稱加密還提供了一定程度的身份驗證,因爲用一個對稱密鑰加密的數據不能用任何其他對稱密鑰解密。因此,只要對稱密鑰由使用它加密通信的雙方保密,任何一方都可以確保它正在與另一方通信。
使用對稱密鑰,你可以與另一個受信任的參與者交換密鑰。你可以確信在參與者之間交換的任何消息(這些消息是用特定密鑰加密的)只能由擁有該密鑰的其他參與者解密。這樣,祕鑰就必須對每個參與者保密。因此,這些密鑰也稱爲祕鑰密碼。如果其他人發現了密鑰,則會影響機密性和身份驗證。
對稱加密的主要缺點是交換密鑰,因爲任何交換都必須保留密鑰的隱私。這通常意味着密匙必須用另一個密匙加密,並且接收方必須已經擁有解密加密密匙所需的密匙。
AES
AES
(Advanced Encryption Standard
,高級加密標準))是美國政府爲保護機密信息而選擇的對稱分組密碼,在全世界的軟件和硬件中實施以加密敏感數據。
美國國家標準與技術研究院(NIST
)於1997年開始開發AES
,當時它宣佈需要一種數據加密標準(DES
)的後繼算法,該算法開始變得容易受到暴力攻擊。2003年6月,美國政府宣佈AES
可用於保護機密信息,並很快成爲保護機密信息的默認加密算法,以及NSA
批准的首個公開訪問和開放密碼的絕密信息。美國國家安全局選擇AES
作爲其信息保障理事會用於保護國家安全系統的加密算法之一。
AES
包括三種分組密碼:AES-128
,AES-192
和AES-256
。每個密碼分別使用128 位,192位和256位的加密密鑰以128 位的塊加密和解密數據。AES
比其前身DES
和3DES
更安全,因爲算法更強大並且使用更長的密鑰長度。它還支持比DES
和3DES
更快的加密,使其成爲需要低延遲或高吞吐量的軟件應用程序,固件和硬件的理想選擇,例如防火牆和路由器。它用於許多協議,如安全套接字層(SSL
)/傳輸層安全性(TLS
),所以可以在大多數需要加密功能的現代應用程序和設備中看到它的應用。
加密和解密:OpenSSL
命令行
要使用帶有OpenSSL
的AES
加密明文,請使用enc命令。以下命令將提示輸入密碼,加密名爲un_encrypted.data
的文件,輸出到encrypted.data
。我們將在此示例中使用密碼12345
。
openssl enc -aes-256-cbc -in un_encrypted.data -out encrypted.data
以下命令將提示輸入密碼,解密名爲encrypted.data
的文件,輸出到un_encrypted.data
。我們將在此示例中使用與加密相同的密碼12345
。
openssl enc -d -aes-256-cbc -in encrypted.data -out un_encrypted.data
使用OpenSSL API
加密和解密
我們使用如下Openssl C
語言API
進行AES
(aes-cbc-128,aes-cbc-192,aes-cbc-256
)加密/解密,我們的目標是:
- 生成一個隨機密鑰
- 生成一個隨機
IV
- 加密一個包含
X
字符的常量數據塊,然後解密相同的數據 - 使用十六進制輸出原始的、加密的和解密的數據
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
// a simple hex-print routine. could be modified to print 16 bytes-per-line
static void hex_print(const void* pv, size_t len)
{
const unsigned char * p = (const unsigned char*)pv;
if (NULL == pv)
printf("NULL");
else
{
size_t i = 0;
for (; i<len;++i)
printf("%02X ", *p++);
}
printf("\n");
}
// main entrypoint
int main(int argc, char **argv)
{
int keylength;
printf("Give a key length [only 128 or 192 or 256!]:\n");
scanf("%d", &keylength);
/* generate a key with a given length */
unsigned char aes_key[keylength/8];
memset(aes_key, 0, keylength/8);
if (!RAND_bytes(aes_key, keylength/8))
exit(-1);
size_t inputslength = 0;
printf("Give an input's length:\n");
scanf("%lu", &inputslength);
/* generate input with a given length */
unsigned char aes_input[inputslength];
memset(aes_input, 'X', inputslength);
/* init vector */
unsigned char iv_enc[AES_BLOCK_SIZE], iv_dec[AES_BLOCK_SIZE];
RAND_bytes(iv_enc, AES_BLOCK_SIZE);
memcpy(iv_dec, iv_enc, AES_BLOCK_SIZE);
// buffers for encryption and decryption
const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
unsigned char enc_out[encslength];
unsigned char dec_out[inputslength];
memset(enc_out, 0, sizeof(enc_out));
memset(dec_out, 0, sizeof(dec_out));
// so i can do with this aes-cbc-128 aes-cbc-192 aes-cbc-256
AES_KEY enc_key, dec_key;
AES_set_encrypt_key(aes_key, keylength, &enc_key);
AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv_enc, AES_ENCRYPT);
AES_set_decrypt_key(aes_key, keylength, &dec_key);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv_dec, AES_DECRYPT);
printf("original:\t");
hex_print(aes_input, sizeof(aes_input));
printf("encrypt:\t");
hex_print(enc_out, sizeof(enc_out));
printf("decrypt:\t");
hex_print(dec_out, sizeof(dec_out));
return 0;
}
需要注意的地方包括:
- 適當的密鑰緩衝區大小
- 適當的輸出加密緩衝區大小:必須是塊大小倍數,如果原始源緩衝區是精確的塊大小倍數,則仍需要一個完整的填充塊。
- 相同的祕鑰和
IV
用於加密和解密。
下面是測試結果:
$ gcc openssl_aes.c -o openssl_aes -lssl -lcrypto
$ ./openssl_aes
Give a key length [only 128 or 192 or 256!]:
256
Give an input's length:
20
original: 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58
encrypt: E0 6E 33 9A 35 E0 62 B9 B2 25 9F 44 E0 2E E3 F5 B3 DE 6C C7 FA 32 2C DC B7 C2 44 FA 64 58 BC 4C
decrypt: 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58