128bitのAES暗号化復号化を、、、windows使いならこっちでしょって方法でやったのをメモとして残す。ちなみに、C#からDLL関数を実行の回でつかったDLLはこの方法で作ったものです。特に自分の勉強にもならないんだけど、きっとIT業界では常識すぎるのか、あまり情報がないので。
参考サイト
#include <windows.h> #include <stdint.h> #include <bcrypt.h> //#include <stdio.h> #pragma comment(lib,"Bcrypt.lib") #define NT_SUCCESS(Status) (((NTSTATUS)(Status))>=0) #define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) int __stdcall AES128Encrypt(PBYTE plain,PBYTE key,PBYTE ciphered){ BCRYPT_ALG_HANDLE hAesAlg=NULL; BCRYPT_KEY_HANDLE hKey=NULL; NTSTATUS status=STATUS_UNSUCCESSFUL; DWORD cbCipherText=0; DWORD cbPlainText=0; DWORD cbData=0; DWORD cbKeyObject=0; PBYTE pbCipherText=NULL; PBYTE pbPlainText=NULL; PBYTE pbKeyObject=NULL; size_t size_of_plain=16; size_t size_of_key=16; int ret; status=BCryptOpenAlgorithmProvider(&hAesAlg,BCRYPT_AES_ALGORITHM,NULL,0); if(!NT_SUCCESS(status)){ret=1;goto Cleanup;} status=BCryptGetProperty(hAesAlg,BCRYPT_OBJECT_LENGTH,(PBYTE)&cbKeyObject,sizeof(DWORD),&cbData,0); if(!NT_SUCCESS(status)){ret=2;goto Cleanup;} pbKeyObject=(PBYTE)HeapAlloc(GetProcessHeap(),0,cbKeyObject); if(NULL==pbKeyObject){ret=3;goto Cleanup;} status=BCryptSetProperty(hAesAlg,BCRYPT_CHAINING_MODE,(PBYTE)BCRYPT_CHAIN_MODE_ECB,sizeof(BCRYPT_CHAIN_MODE_ECB),0); if(!NT_SUCCESS(status)){ret=4;goto Cleanup;} status=BCryptGenerateSymmetricKey(hAesAlg,&hKey,pbKeyObject,cbKeyObject,key,size_of_key,0); if(!NT_SUCCESS(status)){ret=5;goto Cleanup;} cbPlainText=size_of_plain; pbPlainText=(PBYTE)HeapAlloc(GetProcessHeap(),0,cbPlainText); if(NULL==pbPlainText){ret=6;goto Cleanup;} memcpy(pbPlainText,plain,size_of_plain); status=BCryptEncrypt(hKey,pbPlainText,cbPlainText,NULL,NULL,0,NULL,0,&cbCipherText,BCRYPT_BLOCK_PADDING); if(!NT_SUCCESS(status)){ret=6;goto Cleanup;} pbCipherText=(PBYTE)HeapAlloc(GetProcessHeap(),0,cbCipherText); if(NULL==pbCipherText){ret=8;goto Cleanup;} status=BCryptEncrypt(hKey,pbPlainText,cbPlainText,NULL,NULL,0,pbCipherText,cbCipherText,&cbData,BCRYPT_BLOCK_PADDING); if(!NT_SUCCESS(status)){ret=9;goto Cleanup;} memcpy(ciphered,pbCipherText,size_of_plain); ret=0; Cleanup: if(hAesAlg){BCryptCloseAlgorithmProvider(hAesAlg,0);} if(hKey){BCryptDestroyKey(hKey);} if(pbCipherText){HeapFree(GetProcessHeap(),0,pbCipherText);} if(pbPlainText){HeapFree(GetProcessHeap(),0,pbPlainText);} if(pbKeyObject){HeapFree(GetProcessHeap(),0,pbKeyObject);} hAesAlg=NULL; hKey=NULL; pbCipherText=NULL; pbPlainText=NULL; pbKeyObject=NULL; //for(int i=0;i<16;i++){printf("%02X",plain[i]);}printf("\n"); //for(int i=0;i<16;i++){printf("%02X",key[i]);}printf("\n"); ///for(int i=0;i<16;i++){printf("%02X",ciphered[i]);}printf("\n"); return ret; } int __stdcall AES128Decrypt(PBYTE ciphered,PBYTE key,PBYTE plain){ BCRYPT_ALG_HANDLE hAesAlg=NULL; BCRYPT_KEY_HANDLE hKey=NULL; NTSTATUS status=STATUS_UNSUCCESSFUL; DWORD cbCipherText=0; DWORD cbPlainText=0; DWORD cbData=0; DWORD cbKeyObject=0; PBYTE pbCipherText=NULL; PBYTE pbPlainText=NULL; PBYTE pbKeyObject=NULL; size_t size_of_ciphered=16; size_t size_of_key=16; int ret; status=BCryptOpenAlgorithmProvider(&hAesAlg,BCRYPT_AES_ALGORITHM,NULL,0); if(!NT_SUCCESS(status)){ret=1;goto Cleanup;} status=BCryptGetProperty(hAesAlg,BCRYPT_OBJECT_LENGTH,(PBYTE)&cbKeyObject,sizeof(DWORD),&cbData,0); if(!NT_SUCCESS(status)){ret=2;goto Cleanup;} pbKeyObject=(PBYTE)HeapAlloc(GetProcessHeap(),0,cbKeyObject); if(NULL==pbKeyObject){ret=3;goto Cleanup;} status=BCryptSetProperty(hAesAlg,BCRYPT_CHAINING_MODE,(PBYTE)BCRYPT_CHAIN_MODE_ECB,sizeof(BCRYPT_CHAIN_MODE_ECB),0); if(!NT_SUCCESS(status)){ret=4;goto Cleanup;} status=BCryptGenerateSymmetricKey(hAesAlg,&hKey,pbKeyObject,cbKeyObject,key,size_of_key,0); if(!NT_SUCCESS(status)){ret=5;goto Cleanup;} cbCipherText=size_of_ciphered; pbCipherText=(PBYTE)HeapAlloc(GetProcessHeap(),0,cbCipherText); if(NULL==pbCipherText){ret=6;goto Cleanup;} memcpy(pbCipherText,ciphered,size_of_ciphered); status=BCryptDecrypt(hKey,pbCipherText,cbCipherText,NULL,NULL,0,NULL,0,&cbPlainText,0); if(!NT_SUCCESS(status)){ret=6;goto Cleanup;} pbPlainText=(PBYTE)HeapAlloc(GetProcessHeap(),0,cbPlainText); if(NULL==pbPlainText){ret=8;goto Cleanup;} status=BCryptDecrypt(hKey,pbCipherText,cbCipherText,NULL,NULL,0,pbPlainText,cbPlainText,&cbData,0); if(!NT_SUCCESS(status)){ret=9;goto Cleanup;} memcpy(plain,pbPlainText,size_of_ciphered); ret=0; Cleanup: if(hAesAlg){BCryptCloseAlgorithmProvider(hAesAlg,0);} if(hKey){BCryptDestroyKey(hKey);} if(pbCipherText){HeapFree(GetProcessHeap(),0,pbCipherText);} if(pbPlainText){HeapFree(GetProcessHeap(),0,pbPlainText);} if(pbKeyObject){HeapFree(GetProcessHeap(),0,pbKeyObject);} hAesAlg=NULL; hKey=NULL; pbCipherText=NULL; pbPlainText=NULL; pbKeyObject=NULL; return ret; } #include <stdio.h> int main(int argc,char** argv){ uint8_t key[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; uint8_t data[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff}; uint8_t ciphered[16]; uint8_t invciphered[16]; AES128Encrypt(data,key,ciphered); for(int i=0;i<16;i++){ printf("%02X",ciphered[i]); } printf("\n"); AES128Decrypt(ciphered,key,invciphered); for(int i=0;i<16;i++){ printf("%02X",invciphered[i]); } printf("\n"); }
でけた(๑•̀д•́๑)
相変わらずコメントなし。コードの行数は自力で書いたのと大して変わらないかな、、、
Decryptの時に、dwFlagsをBCRYPT_BLOCK_PADDINGでなく0にしないといけなかったのがはまりどころ。オプション設定とかが色々あって面倒だけど、参考ページをじっくり読めばまぁそう難しくない。自力で実装するよりは全然ラク。
処理時間を計測してみる。
#include <stdio.h> #include <time.h> int main(int argc,char** argv){ uint8_t key[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; uint8_t data[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff}; uint8_t ciphered[16]; uint8_t invciphered[16]; clock_t start_clock, end_clock; start_clock = clock(); for(int i=0;i<1000000;i++){ AES128Encrypt(data,key,ciphered); } end_clock = clock(); printf("clock:%f\n",(double)(end_clock-start_clock)/CLOCKS_PER_SEC); for(int i=0;i<16;i++){ printf("%02X",ciphered[i]); } printf("\n"); AES128Decrypt(ciphered,key,invciphered); for(int i=0;i<16;i++){ printf("%02X",invciphered[i]); } printf("\n"); }
main関数をこんな感じに変更して実行すると、
1M回の計算に1.222sかかっている。すなわち、1回あたり1.222usかかっている。
では自作した方は、、、同じように測定してみると、1回あたり8.746us!!実用上はMicrosoftに乗っかるのが正解TT
コメントをお書きください