I'm building a RESTful server using Delphi XE8 with LockBox 3 for encryption. I use AES to encrypt data (JSON) and send it to an Adroid device - Client.
If I send the encrypted data to client and the client knows the encryption key, how could he decrypt the data without knowing the IV because it auto managed by LB3 internally?
I'm using Delphi XE8
First: I installed LockBox last version.
Second: there is no documentation on how to set the IV.
I managed to get the IV (first 8 bytes from ciphertext):
function TAESEnrypt.EncryptAES_String(const str: string): string;
var
Codec1: TCodec;
CryptographicLibrary1: TCryptographicLibrary;
bt:TByteArray;
m:TMemoryStream;
AEncoding: TEncoding;
pCipher: TBytes;
bytes: TBytes;
text: string;
Encoding: TEncoding;
iv:TBytes;
cipher:TBytes;
i:integer;
begin
Result:='';
KeyHex:='';
KeyBin:=TMemoryStream.Create;
Codec1 := TCodec.Create( nil);
CryptographicLibrary1 := TCryptographicLibrary.Create( nil);
Codec1.CryptoLibrary := CryptographicLibrary1;
Codec1.StreamCipherId := BlockCipher_ProgId;
Codec1.BlockCipherId := 'native.AES-128';
Codec1.ChainModeId := CBC_ProgId;
Codec1.Password := Password;
Codec1.EncryptString(str, CipherText, TEncoding.UTF8);
Result:=CipherText;
Codec1.Key.SaveToStream(KeyBin);
Codec1.Free;
CryptographicLibrary1.Free;
//key ==> HEX
KeyBin.Position:=0;
SetLength(KeyHex,KeyBin.Size*2);
SetLength(bt, KeyBin.Size);
KeyBin.Read(bt[0],KeyBin.Size);
KeyBin.Position:=0;
BinToHex(bt[0],pchar(KeyHex),KeyBin.Size);
//key ==> base64
Key64:=TNetEncoding.Base64.EncodeBytesToString(bt);
//
{
Ciphertext = Base64
IV ==> Extract the first 8 bytes (64 bits)
1. Base64 ==> Binary
2. get IV
3. Binary ==> Base64 (Ciphertext)
4. Binary ==> Base64 (IV)
5. Binary ==> HEX (Ciphertext)
6. Binary ==> HEX (IV)
}
bytes := TNetEncoding.Base64.DecodeStringToBytes(CipherText);//result => binary data
iv:=Copy(bytes,0,8);//get first 8 bytes (iv) => binary data
cipher:=Copy(bytes,8,Length(bytes)-8);//the rest is the encrypted data => binary data
//Bin => base64
iv64:=TNetEncoding.Base64.EncodeBytesToString(iv);
cipher64:=TNetEncoding.Base64.EncodeBytesToString(cipher);
//Bin => HEX
SetLength(ivHex,Length(iv)*2);
BinToHex(iv[0],pchar(ivHex),Length(iv));
SetLength(CipherHex,Length(cipher));
BinToHex(Cipher[0],pchar(CipherHex),Length(Cipher));
end;
For example (128):
iv_64 : P7NJIfhws2k=
iv_hex: 3FB34921F870B369
cipher_64 : 5UvFMw==
cipher_hex: E54B
Key_64 : /dn9yyUOTWobOQx1A+ZfAg==
Key_hex: FDD9FDCB250E4D6A1B390C7503E65F02
On the client side (Android) I get the error "Bad base 64" or "last block incomplete in decryption" and here is my code (it's only for testing):
[I complete the IV with zeros]
byte[] out=new byte[16];
byte[] zero="00000000".getBytes();
byte[] ivBytes; byte[] keyBytes; byte[] textBytes;
ivBytes=Base64.decode("9pdfnd4JvpI=".getBytes("UTF-8"),Base64.DEFAULT);
System.arraycopy(ivBytes,0,out,0,ivBytes.length);
System.arraycopy(zero,0,out,ivBytes.length,zero.length);
keyBytes=Base64.decode("/dn9yyUOTWobOQx1A+ZfAg==".getBytes("UTF-8"),Base64.DEFAULT);
textBytes=Base64.decode("+JnDcw==".getBytes("UTF-8"),Base64.DEFAULT);
AlgorithmParameterSpec ivSpec = new IvParameterSpec(out);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
cipher.init(Cipher.DECRYPT_MODE, newKey,ivSpec);
byte[] decodedBytes = cipher.doFinal(textBytes);
String plain=new String(decodedBytes,"UTF-8");
When I run this in Android I get: "last block incomplete in decryption" and when I remove the "UTF-8" from getBytes() I get "bad base-64", and I don't know how to solve it, any idea?