24 Aug 2006

Linux AES programming with OpenSSL

Advanced Encryption Standard(AES), aka Rijndael, 是作为加密标准被美国政府采用的一种 block 加密算法。2000 年左右,US 为了寻找日渐落后的 DES 的继承者,组织了以此加密算法大比武,经过两轮混战,2001 年 11 月,Rijndael 被接纳为正式标准,这一过程 Wikipedia 有详细介绍。

Block ciphers 是一种对称密钥算法,这种算法使用一种不变的算法处理固定长度的 bits(被称为 blocks),我听说过的有: AES, Blowfish, DES, Twofish。AES 的 block size 固定为 128 bits;生成的密钥长度可以为 128, 192, 256。

对称密钥算法使用同一个密钥进行加密、解密。相对应的有非对称密钥算法,拥有公钥和私钥。

Wikipedia 对 AES 有图文并茂的介绍,相当出色,配合这个 javascript 演示界面,理解起来更加容易。

和前辈 DES 相比,AES 具有更好的安全性和速度,并且被美国政府作为标准推广,其应用日益普遍。但 AES 是一种足够安全的算法吗?目前还没有 AES 的重大过失出现,不过这里提出了挑战。

OK,看看在 Linux 下怎么使用 OpenSSL 进行 AES 加密/解密:
/*
* aes.c - AES encrypt and decrypt examples, using OpenSSL.
* by Jick Nan @ Aug-24, 2006
*
* Process:
* 1) Get INTERFACE's MAC Address (last 3 bytes);
* 2) Padding it to 16 bytes(key16);
* 3) Generate key used to encrypt, using key16 by AES-way;
* 4) AES encrypt, using key16 as message(out);
* 5) Generate key used to decrypt, using key16;
* 4) AES decypt, using out as message(key16).
*
* Compile:
* gcc -Wall aes.c -o aes -lcrypto
*/

#include <stdio.h>
#include <stdlib.h >
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <openssl/aes.h>

#define INTERFACE "eth0"
#define PAD_SIZE 32

int main(void)
{
int skfd;
int i, ret, j;
struct ifreq ifr;
unsigned char pmac[34] = { 0 }; // MAC Address (last 3 bytes)
unsigned char tmp[128] = { 0 };
unsigned char key16[16] = { 0 };// Message to encrypt.
// *CAREFUL* this also used as AES key!
unsigned char out[16] = { 0 }; // Message after encrypted.
unsigned char sout[34] = { 0 }; // String style, rather than HEX
AES_KEY key; // key in AES way

// get MAC address (last three bytes)
skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd == -1) {
printf("L%d: Open socket error!\n", __LINE__);
return -1;
}

strcpy(ifr.ifr_name, INTERFACE);
ret = ioctl(skfd, SIOCGIFHWADDR, &ifr);
if (ret < 0) {
printf("L%d: ioctl error!\n", __LINE__);
return -1;
}
sprintf(pmac, "%02X%02X%02X", (ifr.ifr_hwaddr.sa_data[3] & 0377),
(ifr.ifr_hwaddr.sa_data[4] & 0377),
(ifr.ifr_hwaddr.sa_data[5] & 0377));

printf("pmac(%d)\t\t=\t%s(STR)\n", strlen(pmac), pmac);

// padding to PAD_SIZE bytes
printf("\n>>Padding...\n");
for (i = PAD_SIZE/6; i >= 0; i--) {
strcat(tmp, pmac);
}
strncpy(pmac, tmp, PAD_SIZE);
printf(" tmp(%d)\t=\t%s(STR)\npmac(%d)\t=\t%s(STR)\n",
strlen(tmp), tmp, strlen(pmac), pmac);
// convert string to hex.
for (i = 0, j = 0; i < 32; i+=2, j++) {
tmp[0]='\0';
strncat(tmp, (const char *)(pmac+i), 2);
key16[j] = strtol(tmp, NULL, 16);
}
printf("key16[16]\t=\t");
for (i = 0; i < 16; i++){
printf("%02X", key16[i]);
}
printf("(HEX)\n");

// AES encryption
printf("\n>>AES encryption...\n");
ret = AES_set_encrypt_key((const unsigned char *)key16, 128, &key);
if (ret < 0 ) {
printf("L%d: AES_set_encrypt_key error!\n", __LINE__);
return -1;
}
AES_encrypt((const unsigned char *)key16, (unsigned char *)out, &key);
printf(" out[16]\t=\t");
for (i = 0; i < 16; i++) {
printf("%02X", out[i]);
}
printf("(HEX)\n");
// convert Hex. to string
for (i = 0; i < 16; i++) {
tmp[0] = '\0';
sprintf(tmp, "%02X", out[i]);
strcat(sout, tmp);
}
printf("sout(%d)\t=\t%s(STR)\n", strlen(sout), sout);

// AES decryption
printf("\n>>AES decryption...\n");
ret = AES_set_decrypt_key((const char *)key16, 128, &key);
if (ret < 0 ) {
printf("L%d: AES_set_decrypt_key error!\n", __LINE__);
return -1;
}
key16[0] = '\0'; // Init it as we used it for decryption.
AES_decrypt((const unsigned char *)out, (unsigned char *)key16, &key);
printf("key16[16]\t=\t");
for (i = 0; i < 16; i++){
printf("%02X", key16[i]);
}
printf("(HEX)\n");

return 0;
}

/*
* vim:foldmethod=marker:shiftwidth=8:tabstop=8:filetype=c:norl:
*/

1 comment:

  1. welcome to the wow power leveling cheap wow power leveling service site, buy cheap wow gold,wotlk gold,world of warcraft power leveling buy wow gold|*|wow gold|*|http://www.eing.com

    ReplyDelete