AES暗号復号ができるユニット(クラス) ~Delphiソースコード集
(OpenSSLを使ってAES暗号化復号化したい場合は DelphiでOpenSSLを使って暗号化、復号化を行う を参照)
使用方法
ページ下部にMam.AES ユニットのソース一式を表示しています。ファイル名「Mam.AES.pas」で保存して
uses Mam.AES;
で使用できます。(多分Delphi XE8以降で使用できます。)
推奨するモードは、AES-128-CBC、AES-192-CBC、AES-256-CBC、AES-128-CTR、AES-192-CTR、AES-256-CTRです。
AES-128-ECB、AES-192-ECB、AES-256-ECBは推奨しません。
また乱数生成などによるSalt値を使用することを推奨します。
ブロックサイズ | 鍵長 | 初期化ベクトルIV | |
AES-128-ECB | 128Bit(16Byte) | 128Bit(16Byte) | 無し |
AES-192-ECB | 128Bit(16Byte) | 192Bit(24Byte) | 無し |
AES-256-ECB | 128Bit(16Byte) | 256Bit(32Byte) | 無し |
AES-128-CBC | 128Bit(16Byte) | 128Bit(16Byte) | 128Bit(16Byte) |
AES-192-CBC | 128Bit(16Byte) | 192Bit(24Byte) | 128Bit(16Byte) |
AES-256-CBC | 128Bit(16Byte) | 256Bit(32Byte) | 128Bit(16Byte) |
AES-128-CTR | 128Bit(16Byte) | 128Bit(16Byte) | 128Bit(16Byte) |
AES-192-CTR | 128Bit(16Byte) | 192Bit(24Byte) | 128Bit(16Byte) |
AES-256-CTR | 128Bit(16Byte) | 256Bit(32Byte) | 128Bit(16Byte) |
(1)使用例 AES-128-ECB(非推奨)
AESでECBの場合は初期化ベクトルIVを使用しない。uses Mam.AES, System.NetEncoding; procedure TForm1.Button1Click(Sender: TObject); var aes:TMamAes; data,password:String; dec,key,enc:TBytes; st:string; begin //暗号化するデータ data:='この文字列を暗号化します'; //暗号化パスワード(そのまま鍵とする 16バイト) password:='1234567890123456'; //暗号化するデータの準備(UTF8文字列としてバイナリ配列を取得する) dec:=TEncoding.UTF8.GetBytes(data); key:=TEncoding.ASCII.GetBytes(password);//暗号化鍵 aes:=TMamAes.Create(TMamAesType.MamAES128ECB); //AES-128-ECBの暗号化を行う enc:=aes.Encrypt(dec,key); //AES-128-ECBの復号化を行う dec:=aes.Decrypt(enc,key); //復号化したデータ(バイト配列)をUTF8文字列に変換する st:=TEncoding.UTF8.GetString(dec); showmessage(st); aes.Free; end;
(2)使用例2 AES-192-CBC
OpenSSLと同じようにSalt値を乱数で生成し、パスワード+ソルト値からMD5ハッシュで鍵を生成し、 IVをMD5ハッシュで生成して暗号化復号化する関数を使うuses Mam.AES, System.NetEncoding; procedure TForm1.Button1Click(Sender: TObject); var aes:TMamAes; data,password:String; dec,enc:TBytes; st:string; begin aes:=TMamAes.Create(TmamAesType.MamAES192CBC); data:='日本語で機種依存文字㈱㈲㌔①②③でも使える'; dec:=TEncoding.UTF8.GetBytes(data); password:='abcdefghijklmnop'; //暗号化を行う enc:=aes.OpenSslEncrypt(dec,password); //復号化を行う dec:=aes.OpenSslDecrypt(enc,password); st:=TEncoding.UTF8.GetString(dec); showmessage(st); aes.Free; end;
Mam.AES.pas
// 2020/12/03 CTRのバグ修正 // 2020/11/24 バグ修正 unit Mam.AES; interface uses Winapi.Windows,system.SysUtils; type TMamAesType=( MamAES128ECB,MamAES192ECB,MamAES256ECB, MamAES128CBC,MamAES192CBC,MamAES256CBC, MamAES128CTR,MamAES192CTR,MamAES256CTR ); TAesMatrix44=array[0..3] of array[0..3]of byte; PAesMatrix44=^TAesMatrix44; TMamAes=class(TObject) private fAesType:TMamAesType; fKeyNum:Byte; //鍵長 fKey:TBytes; //鍵配列(128,192,256Bitの何れか) fIV:TBytes; //CBC、CTR時の初期ベクトル(128Bit固定) fNumOfRound:Byte;//必要なラウンド処理の数 //fRound:Byte; //現在のラウンド数 fNk:Byte; //鍵長がNb(4バイト)単位でいくつになるか fRoundKey:TBytes;//ラウンド鍵 fData:TBytes; //暗号化復号化するデータを保持 fIsECB:Boolean; //ECB fIsCBC:Boolean; //CBC fIsCTR:Boolean; //CTR //Round用の鍵を生成する procedure KeyExpansion(); //初期ベクトルIVの設定 procedure SetIv(iv:TBytes); //暗号復号種類(ECB128,CBC128等)の設定 procedure SetAesType(AesType:TMamAesType); //IVとの排他論理和を行う procedure XorIV(buf:PByte); procedure Cipher(State:PAesMatrix44); procedure invCipher(State:PAesMatrix44); procedure AddRoundKey(Round:Byte;State:PAesMatrix44); procedure SubBytes(State:PAesMatrix44); procedure InvSubBytes(State:PAesMatrix44); procedure ShiftRows(State:PAesMatrix44); procedure InvShiftRows(State:PAesMatrix44); procedure MixColumns(State:PAesMatrix44); procedure InvMixColumns(State:PAesMatrix44); function Multiply(x,y:Byte):Byte; function XTime(x:byte):byte; public //コンストラクタ constructor Create(AesType:TMamAesType); //暗号化 function Encrypt(data,key:TBytes):TBytes;overload; function Encrypt(data,key,iv:TBytes):TBytes;overload; //復号化 function Decrypt(data,key:TBytes):TBytes;overload; function Decrypt(data,key,iv:TBytes):TBytes;overload; //Base64Encode function Base64Encode(data:TBytes):String; //Base64Decode function Base64Decode(data:String):TBytes; //OpenSSLと同じようにSalt値を乱数で生成し、 //パスワード+ソルト値からMD5ハッシュで鍵を生成し、 //IVをMD5ハッシュで生成して暗号化復号化する関数 function OpenSslEncrypt(data:TBytes;Password:String):TBytes; function OpenSslDecrypt(data:TBytes;Password:String):TBytes; end; implementation uses System.Hash, ////Delphi XE8以降で使えるユニット System.NetEncoding; const //AESの列数(4バイト単位で暗号化する) Nb:Byte=4; //AESのブロックサイズ(128Bit[16バイト]固定) AES_BlockSize:Byte=16; const SBox:array[0..255]of byte=( $63, $7c, $77, $7b, $f2, $6b, $6f, $c5, $30, $01, $67, $2b, $fe, $d7, $ab, $76, $ca, $82, $c9, $7d, $fa, $59, $47, $f0, $ad, $d4, $a2, $af, $9c, $a4, $72, $c0, $b7, $fd, $93, $26, $36, $3f, $f7, $cc, $34, $a5, $e5, $f1, $71, $d8, $31, $15, $04, $c7, $23, $c3, $18, $96, $05, $9a, $07, $12, $80, $e2, $eb, $27, $b2, $75, $09, $83, $2c, $1a, $1b, $6e, $5a, $a0, $52, $3b, $d6, $b3, $29, $e3, $2f, $84, $53, $d1, $00, $ed, $20, $fc, $b1, $5b, $6a, $cb, $be, $39, $4a, $4c, $58, $cf, $d0, $ef, $aa, $fb, $43, $4d, $33, $85, $45, $f9, $02, $7f, $50, $3c, $9f, $a8, $51, $a3, $40, $8f, $92, $9d, $38, $f5, $bc, $b6, $da, $21, $10, $ff, $f3, $d2, $cd, $0c, $13, $ec, $5f, $97, $44, $17, $c4, $a7, $7e, $3d, $64, $5d, $19, $73, $60, $81, $4f, $dc, $22, $2a, $90, $88, $46, $ee, $b8, $14, $de, $5e, $0b, $db, $e0, $32, $3a, $0a, $49, $06, $24, $5c, $c2, $d3, $ac, $62, $91, $95, $e4, $79, $e7, $c8, $37, $6d, $8d, $d5, $4e, $a9, $6c, $56, $f4, $ea, $65, $7a, $ae, $08, $ba, $78, $25, $2e, $1c, $a6, $b4, $c6, $e8, $dd, $74, $1f, $4b, $bd, $8b, $8a, $70, $3e, $b5, $66, $48, $03, $f6, $0e, $61, $35, $57, $b9, $86, $c1, $1d, $9e, $e1, $f8, $98, $11, $69, $d9, $8e, $94, $9b, $1e, $87, $e9, $ce, $55, $28, $df, $8c, $a1, $89, $0d, $bf, $e6, $42, $68, $41, $99, $2d, $0f, $b0, $54, $bb, $16 ); InvSBox:array[0..255]of byte=( $52, $09, $6a, $d5, $30, $36, $a5, $38, $bf, $40, $a3, $9e, $81, $f3, $d7, $fb, $7c, $e3, $39, $82, $9b, $2f, $ff, $87, $34, $8e, $43, $44, $c4, $de, $e9, $cb, $54, $7b, $94, $32, $a6, $c2, $23, $3d, $ee, $4c, $95, $0b, $42, $fa, $c3, $4e, $08, $2e, $a1, $66, $28, $d9, $24, $b2, $76, $5b, $a2, $49, $6d, $8b, $d1, $25, $72, $f8, $f6, $64, $86, $68, $98, $16, $d4, $a4, $5c, $cc, $5d, $65, $b6, $92, $6c, $70, $48, $50, $fd, $ed, $b9, $da, $5e, $15, $46, $57, $a7, $8d, $9d, $84, $90, $d8, $ab, $00, $8c, $bc, $d3, $0a, $f7, $e4, $58, $05, $b8, $b3, $45, $06, $d0, $2c, $1e, $8f, $ca, $3f, $0f, $02, $c1, $af, $bd, $03, $01, $13, $8a, $6b, $3a, $91, $11, $41, $4f, $67, $dc, $ea, $97, $f2, $cf, $ce, $f0, $b4, $e6, $73, $96, $ac, $74, $22, $e7, $ad, $35, $85, $e2, $f9, $37, $e8, $1c, $75, $df, $6e, $47, $f1, $1a, $71, $1d, $29, $c5, $89, $6f, $b7, $62, $0e, $aa, $18, $be, $1b, $fc, $56, $3e, $4b, $c6, $d2, $79, $20, $9a, $db, $c0, $fe, $78, $cd, $5a, $f4, $1f, $dd, $a8, $33, $88, $07, $c7, $31, $b1, $12, $10, $59, $27, $80, $ec, $5f, $60, $51, $7f, $a9, $19, $b5, $4a, $0d, $2d, $e5, $7a, $9f, $93, $c9, $9c, $ef, $a0, $e0, $3b, $4d, $ae, $2a, $f5, $b0, $c8, $eb, $bb, $3c, $83, $53, $99, $61, $17, $2b, $04, $7e, $ba, $77, $d6, $26, $e1, $69, $14, $63, $55, $21, $0c, $7d ); RCon:array[0..10]of byte=( $8d, $01, $02, $04, $08, $10, $20, $40, $80, $1b, $36); MamBase64: String = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'+ 'abcdefghijklmnopqrstuvwxyz'+ '0123456789+/'; { TMamAes } procedure TMamAes.AddRoundKey(Round: Byte; State: PAesMatrix44); var i,j:Cardinal; begin for i := 0 to 3 do for j := 0 to 3 do state^[i][j]:=State^[i][j] xor fRoundKey[(Round*Nb*4)+(i*Nb)+j]; end; function TMamAes.Base64Decode(data:String):TBytes; var i,Len:integer; b:byte; i1,i2,i3,i4:integer; begin SetLength(Result,0); i:=0; Len:=length(data); while i<Len do begin i1:=Pos(data.Substring(i,1),MamBase64)-1; inc(i); i2:=Pos(data.Substring(i,1),MamBase64)-1; inc(i); i3:=Pos(data.Substring(i,1),MamBase64)-1; inc(i); i4:=Pos(data.Substring(i,1),MamBase64)-1; if i3=-1 then begin b:=(i1 shl 2)+((i2 and $30) shr 4); SetLength(Result,Length(Result)+1); Result[Length(Result)-1]:=b; end else if i4=-1 then begin b:=(i1 shl 2)+((i2 and $30) shr 4); SetLength(Result,Length(Result)+1); Result[Length(Result)-1]:=b; b:=((i2 and $0f) shl 4) + ((i3 and $3c) shr 2); SetLength(Result,Length(Result)+1); Result[Length(Result)-1]:=b; end else begin b:=(i1 shl 2)+((i2 and $30) shr 4); SetLength(Result,Length(Result)+1); Result[Length(Result)-1]:=b; b:=((i2 and $0f) shl 4) + ((i3 and $3c) shr 2); SetLength(Result,Length(Result)+1); Result[Length(Result)-1]:=b; b:=((i3 and $03) shl 6)+ (i4 and $3f); SetLength(Result,Length(Result)+1); Result[Length(Result)-1]:=b; end; inc(i); end; end; function TMamAes.Base64Encode(data: TBytes): String; var i,Len:Cardinal; enc:array[0..3] of String; b1,b2,b3:byte; begin Len:=Length(data); result:=''; i:=0; while i<Len do begin enc[0]:=''; enc[1]:=''; enc[2]:=''; enc[3]:=''; //ZeroMemory(@enc,4); b1:=data[i]; enc[0]:=MamBase64.Substring((b1 and $fc) shr 2,1); inc(i); if i>=Len then begin enc[1]:=MamBase64.Substring((b1 and $3) shl 4,1); enc[2]:='='; enc[3]:='='; end else begin b2:=data[i]; enc[1]:=MamBase64.Substring(((b1 and $3) shl 4 )+((b2 and $f0) shr 4),1); inc(i); if i>=Len then begin enc[2]:=MamBase64.Substring((b2 and $f) shl 2,1); enc[3]:='='; end else begin b3:=data[i]; enc[2]:=MamBase64.Substring(((b2 and $f) shl 2)+((b3 and $c0) shr 6),1); enc[3]:=MamBase64.Substring(b3 and $3f,1); end; end; Result:=Result+enc[0]+enc[1]+enc[2]+enc[3]; inc(i); end; end; procedure TMamAes.Cipher(State: PAesMatrix44); var Round:Byte; begin Round:=0; AddRoundKey(Round,State); inc(round); while true do begin SubBytes(State); shiftrows(State); if Round>=fNumOfRound then break; mixcolumns(State); AddRoundKey(Round,State); inc(Round); end; AddRoundKey(Round,State); end; procedure TMamAes.InvCipher(State: PAesMatrix44); var Round:byte; begin AddRoundKey(fNumOfRound,State); Round:=fNumOfRound-1; while true do begin InvShiftRows(State); InvSubBytes(State); AddRoundKey(Round,State); if round=0 then break; InvMixColumns(state); dec(Round); end; end; constructor TMamAes.Create(AesType:TMamAesType); //コンストラクタ begin inherited Create(); setLength(fIV,AES_BlockSize); ZeroMemory(fIV,AES_BlockSize); SetAesType(AesType); end; function TMamAes.Decrypt(data, key: TBytes):TBytes; var i,len,bi:Cardinal; NextIv:TBytes; buf:TBytes; begin //鍵の設定 len:=Length(key); SetLength(fkey,fKeyNum); ZeroMemory(@fkey[0],fKeyNum); if len>fKeyNum then len:=fKeyNum; move(key[0],fkey[0],len); KeyExpansion(); //復号化するデータを保存 len:=length(data); SetLength(fData,len); ZeroMemory(fData,len); Move(data[0],fData[0],len); if fIsECB or fIsCBC then begin //AES-ECB 又は AES-CBCの場合 setlength(NextIv,AES_BlockSize); i:=0; while i<len do begin move(fData[i],NextIv[0],AES_BlockSize); invCipher(PAesMatrix44(@fData[i])); if fIsCBC then begin XorIv(@fData[i]); move(NextIv[0],fIV[0],AES_BlockSize); end; inc(i,AES_BlockSize); end; //#PKCS7 len:=len-fData[len-1]; setlength(fData,len); end else begin //AES-CTRの場合 i:=0; bi:=AES_BlockSize; setlength(buf,AES_BlockSize); while i<len do begin if bi=AES_BlockSize then begin Move(fIV[0],buf[0],AES_BlockSize); Cipher(PAesMatrix44(@buf[0])); for bi := (AES_BlockSize-1) downto 0 do begin if (fIV[bi]=255) then begin fIV[bi]:=0; end else begin inc(fIV[bi]); break; end; end; bi:=0; end; fData[i] := (fData[i] xor buf[bi]); inc(i); inc(bi); end; end; Result:=fData; end; function TMamAes.Decrypt(data, key, iv: TBytes):TBytes; begin SetIv(iv); Result:=Decrypt(data,key); end; function TMamAes.Encrypt(data, key: TBytes):TBytes; var i,bi:Cardinal; Len:Cardinal; LenPKCS7:Cardinal; buf:TBytes; begin //鍵の設定 Len:=Length(key); SetLength(fkey,fKeyNum); ZeroMemory(@fkey[0],fKeyNum); if Len>fKeyNum then Len:=fKeyNum; move(key[0],fkey[0],Len); KeyExpansion(); //暗号化するデータを保存 Len:=length(data); SetLength(fData,Len); ZeroMemory(fData,Len); Move(data[0],fData[0],Len); if fIsECB or fIsCBC then begin //AES-ECB 又は AES-CBCの場合 //#PKCS7 パディング LenPKCS7:=(Len div 16 * 16)+16; setlength(fData,LenPKCS7); for i := Len to LenPKCS7-1 do fData[i]:=byte(LenPKCS7-Len); Len:=LenPKCS7; i:=0; while i<Len do begin if fIsCBC then self.XorIV(@fData[i]); self.Cipher(PAesMatrix44(@fData[i])); if fIsCBC then Move(fData[i],fIV[0],AES_BlockSize); Inc(i,AES_BlockSize); end; end else begin //AES-CTRの場合 i:=0; bi:=AES_BlockSize; setlength(buf,AES_BlockSize); while i<len do begin if bi=AES_BlockSize then begin Move(fIV[0],buf[0],AES_BlockSize); Cipher(PAesMatrix44(@buf[0])); for bi := (AES_BlockSize-1) downto 0 do begin if (fIV[bi]=255) then begin fIV[bi]:=0; end else begin inc(fIV[bi]); break; end; end; bi:=0; end; fData[i] := (fData[i] xor buf[bi]); inc(i); inc(bi); end; end; result:=fData; end; function TMamAes.Encrypt(data, key, iv: TBytes):TBytes; begin self.SetIv(iv); result:=self.Encrypt(data,key); end; procedure TMamAes.KeyExpansion; var AES_keyExpSize:Cardinal; i,j,k:Cardinal; tmp:array[0..3] of Byte; b:Byte; begin AES_keyExpSize:=176+32*0; if fNumOfRound=10 then AES_keyExpSize:=176+32*0; if fNumOfRound=12 then AES_keyExpSize:=176+32*1; if fNumOfRound=14 then AES_keyExpSize:=176+32*2; SetLength(fRoundKey,AES_keyExpSize); for i := 0 to fNk-1 do begin fRoundKey[i*4+0]:=fKey[i*4+0]; fRoundKey[i*4+1]:=fKey[i*4+1]; fRoundKey[i*4+2]:=fKey[i*4+2]; fRoundKey[i*4+3]:=fKey[i*4+3]; end; for i := fNk to Nb*(fNumOfRound+1)-1 do begin k:=(i-1)*4; tmp[0]:=fRoundKey[k+0]; tmp[1]:=fRoundKey[k+1]; tmp[2]:=fRoundKey[k+2]; tmp[3]:=fRoundKey[k+3]; if (i mod fNk)=0 then begin b:=tmp[0]; tmp[0]:=tmp[1]; tmp[1]:=tmp[2]; tmp[2]:=tmp[3]; tmp[3]:=b; tmp[0] := sbox[tmp[0]]; tmp[1] := sbox[tmp[1]]; tmp[2] := sbox[tmp[2]]; tmp[3] := sbox[tmp[3]]; tmp[0]:=tmp[0] xor Rcon[i div fNk]; end; if fNumOfRound=14 then begin //aes256 if (i mod fNk)=4 then begin tmp[0] := sbox[tmp[0]]; tmp[1] := sbox[tmp[1]]; tmp[2] := sbox[tmp[2]]; tmp[3] := sbox[tmp[3]]; end; end; j:=i*4; k:=(i-fNk)*4; fRoundKey[j+0]:=fRoundKey[k+0] xor tmp[0]; fRoundKey[j+1]:=fRoundKey[k+1] xor tmp[1]; fRoundKey[j+2]:=fRoundKey[k+2] xor tmp[2]; fRoundKey[j+3]:=fRoundKey[k+3] xor tmp[3]; end; end; procedure TMamAes.MixColumns(State: PAesMatrix44); var i:integer; tmp,tmp1,tmp2:byte; begin for i := 0 to 3 do begin tmp :=State^[i][0]; tmp1:=State^[i][0] xor State^[i][1] xor State^[i][2] xor State^[i][3]; tmp2:=State^[i][0] xor State^[i][1]; tmp2:=XTime(tmp2); State^[i][0]:= State^[i][0] xor tmp2 xor tmp1; tmp2:=State^[i][1] xor State^[i][2]; tmp2:=XTime(tmp2); State^[i][1]:= State^[i][1] xor tmp2 xor tmp1; tmp2:=State^[i][2] xor State^[i][3]; tmp2:=XTime(tmp2); State^[i][2]:= State^[i][2] xor tmp2 xor tmp1; tmp2:=State^[i][3] xor tmp; tmp2:=XTime(tmp2); State^[i][3]:= State^[i][3] xor tmp2 xor tmp1; end; end; procedure TMamAes.InvMixColumns(State: PAesMatrix44); var i:Cardinal; tmp1,tmp2,tmp3,tmp4:byte; begin for i := 0 to 3 do begin tmp1:=State^[i][0]; tmp2:=State^[i][1]; tmp3:=State^[i][2]; tmp4:=State^[i][3]; State^[i][0]:= Multiply(tmp1,$0e) xor Multiply(tmp2,$0b) xor Multiply(tmp3,$0d) xor Multiply(tmp4,$09); State^[i][1]:= Multiply(tmp1,$09) xor Multiply(tmp2,$0e) xor Multiply(tmp3,$0b) xor Multiply(tmp4,$0d); State^[i][2]:= Multiply(tmp1,$0d) xor Multiply(tmp2,$09) xor Multiply(tmp3,$0e) xor Multiply(tmp4,$0b); State^[i][3]:= Multiply(tmp1,$0b) xor Multiply(tmp2,$0d) xor Multiply(tmp3,$09) xor Multiply(tmp4,$0e); end; end; procedure TMamAes.SetAesType(AesType: TMamAesType); //AES種別の設定(ECB,CBC,CTR) begin fIsECB:=False; fIsCBC:=False; fIsCTR:=False; //鍵長の設定 fAesType:=AesType; if (fAesType=MamAES128ECB) or (fAesType=MamAES128CBC) or (fAesType=MamAES128CTR) then fKeyNum:=16 else if (fAesType=MamAES192ECB) or (fAesType=MamAES192CBC) or (fAesType=MamAES192CTR) then fKeyNum:=24 else fKeyNum:=32; if (fAesType=MamAES128ECB) or (fAesType=MamAES192ECB) or (fAesType=MamAES256ECB) then fIsECB:=True; if (fAesType=MamAES128CBC) or (fAesType=MamAES192CBC) or (fAesType=MamAES256CBC) then fIsCBC:=True; if (fAesType=MamAES128CTR) or (fAesType=MamAES192CTR) or (fAesType=MamAES256CTR) then fIsCTR:=True; fNk:=fKeyNum div Nb;//Nb(4バイト)単位でいくつか fNumOfRound:=fNk+6; //ラウンド処理数 end; procedure TMamAes.SetIv(iv: TBytes); var len:Cardinal; //初期ベクトルIVの設定 begin setLength(fIV,AES_BlockSize); ZeroMemory(@fIV[0],AES_BlockSize); len:=length(iv); if len>AES_BlockSize then len:=AES_BlockSize; Move(iv[0],fIV[0],len); end; procedure TMamAes.ShiftRows(State: PAesMatrix44); var tmp:Byte; begin tmp :=State^[0][1]; State^[0][1]:=State^[1][1]; State^[1][1]:=State^[2][1]; State^[2][1]:=State^[3][1]; State^[3][1]:=tmp; tmp :=State^[0][2]; State^[0][2]:=State^[2][2]; State^[2][2]:=tmp; tmp :=State^[1][2]; State^[1][2]:=State^[3][2]; State^[3][2]:=tmp; tmp :=State^[0][3]; State^[0][3]:=State^[3][3]; State^[3][3]:=State^[2][3]; State^[2][3]:=State^[1][3]; State^[1][3]:=tmp; end; procedure TMamAes.InvShiftRows(State: PAesMatrix44); var tmp:Byte; begin tmp :=state^[3][1]; state^[3][1]:=state^[2][1]; state^[2][1]:=state^[1][1]; state^[1][1]:=state^[0][1]; state^[0][1]:=tmp; tmp :=state^[0][2]; state^[0][2]:=state^[2][2]; state^[2][2]:=tmp; tmp :=state^[1][2]; state^[1][2]:=state^[3][2]; state^[3][2]:=tmp; tmp :=state^[0][3]; state^[0][3]:=state^[1][3]; state^[1][3]:=state^[2][3]; state^[2][3]:=state^[3][3]; state^[3][3]:=tmp; end; procedure TMamAes.SubBytes(State: PAesMatrix44); var i,j:integer; begin for i := 0 to 3 do for j := 0 to 3 do State^[j][i]:= SBox[State^[j][i]]; end; procedure TMamAes.InvSubBytes(State: PAesMatrix44); var i,j:integer; begin for i := 0 to 3 do for j := 0 to 3 do State^[j][i]:= InvSBox[State^[j][i]]; end; procedure TMamAes.XorIV(buf: PByte); var i:Cardinal; begin for i := 0 to AES_BlockSize-1 do begin buf^:=buf^ xor fIV[i]; inc(buf); end; end; function TMamAes.Multiply(x, y: Byte): Byte; begin result:=( ((y and 1) * x) xor (((y shr 1) and 1)*xtime(x)) xor (((y shr 2) and 1)*xtime(xtime(x))) xor (((y shr 3) and 1)*xtime(xtime(xtime(x)))) xor (((y shr 4) and 1)*xtime(xtime(xtime(xtime(x))))) ); end; function TMamAes.OpenSslDecrypt(data: TBytes; Password: String): TBytes; var b1,b2,b3:TBytes; pass,salted,salt,iv,pass_salt,key:TBytes; i:Cardinal; flag:boolean; dec:TBytes; md5:THashMD5; data_nosalt:TBytes; begin // 'Salted__'+8バイトのSalt値 //暗号鍵 = MD5(password + salt) //IV = MD5(暗号鍵 + password + salt) result:=dec; if not ((fAesType=TMamAesType.MamAES128CTR) or (fAesType=TMamAesType.MamAES192CTR) or (fAesType=TMamAesType.MamAES256CTR)) then begin if length(data)<32 then exit; end; //ソルト値の処理 salted:=TEncoding.ASCII.GetBytes('Salted__'); flag:=false; for i := 0 to 7 do if data[i]<>salted[i] then flag:=true; if flag then exit; setlength(salt,8); move(data[8],salt[0],8); setlength(data_nosalt,length(data)-16); move(data[16],data_nosalt[0],length(data)-16); //パスワード配列 pass:=TEncoding.ASCII.GetBytes(Password); //pass+saltのバイト配列生成 SetLength(pass_salt,Length(pass)+Length(salt)); Move(pass[0],pass_salt[0],Length(pass)); Move(salt[0],pass_salt[Length(pass)],Length(salt)); md5:=THashMD5.Create; md5.Reset; md5.Update(pass_salt); b1:=md5.HashAsBytes; md5.Reset; setlength(b2,16+Length(pass_salt)); move(b1[0],b2[0],length(b1)); move(pass_salt[0],b2[length(b1)],length(pass_salt)); md5.Update(b2); b2:=md5.HashAsBytes; md5.Reset; setlength(b3,16+Length(pass_salt)); move(b2[0],b3[0],length(b2)); move(pass_salt[0],b3[length(b2)],length(pass_salt)); md5.Update(b3); b3:=md5.HashAsBytes; setlength(iv,16); if fKeyNum=16 then begin setlength(key,16); move(b1[0],key[0],16); move(b2[0],iv[0],16); end else if fKeyNum=24 then begin setlength(key,24); move(b1[0],key[0],16); move(b2[0],key[16],8); move(b2[8],iv[0],8); move(b3[0],iv[8],8); end else begin setlength(key,32); move(b1[0],key[0],16); move(b2[0],key[16],16); move(b3[0],iv[0],16); end; dec:=self.Decrypt(data_nosalt,key,iv); result:=dec; end; function TMamAes.OpenSslEncrypt(data: TBytes; Password: String): TBytes; var i:Cardinal; md5:THashMD5; //Delphi XE8以降で使えるクラス salt,pass,pass_salt:TBytes; b1,b2,b3:TBytes; key,iv:TBytes; enc:TBytes; salted:TBytes; res:TBytes; begin // 'Salted__'+8バイトのSalt値 //暗号鍵 = MD5(password + salt) //IV = MD5(暗号鍵 + password + salt) pass:=TEncoding.ASCII.GetBytes(Password); //ランダムなSalt値の計算 Randomize; SetLength(salt,8); for i := 0 to 7 do salt[i]:=Random(256); //pass+saltのバイト配列生成 SetLength(pass_salt,Length(pass)+Length(salt)); Move(pass[0],pass_salt[0],Length(pass)); Move(salt[0],pass_salt[Length(pass)],Length(salt)); md5:=THashMD5.Create; md5.Reset; md5.Update(pass_salt); b1:=md5.HashAsBytes; md5.Reset; setlength(b2,16+Length(pass_salt)); move(b1[0],b2[0],length(b1)); move(pass_salt[0],b2[length(b1)],length(pass_salt)); md5.Update(b2); b2:=md5.HashAsBytes; md5.Reset; setlength(b3,16+Length(pass_salt)); move(b2[0],b3[0],length(b2)); move(pass_salt[0],b3[length(b2)],length(pass_salt)); md5.Update(b3); b3:=md5.HashAsBytes; setlength(iv,16); if fKeyNum=16 then begin setlength(key,16); move(b1[0],key[0],16); move(b2[0],iv[0],16); end else if fKeyNum=24 then begin setlength(key,24); move(b1[0],key[0],16); move(b2[0],key[16],8); move(b2[8],iv[0],8); move(b3[0],iv[8],8); end else begin setlength(key,32); move(b1[0],key[0],16); move(b2[0],key[16],16); move(b3[0],iv[0],16); end; enc:=self.Encrypt(data,key,iv); salted:=TEncoding.ASCII.GetBytes('Salted__'); setlength(res,length(salted)+length(salt)+length(enc)); move(salted[0],res[0],length(salted)); move(salt[0],res[8],length(salt)); move(enc[0],res[16],length(enc)); result:=res; end; function TMamAes.XTime(x: byte): byte; begin result:=((x shl 1) xor (((x shr 7) and 1) * $1b)); end; end.