In the process of moving from Delphi2007 to XE2, we are thinking about switching encryption libraries from DCPCrypt to Turbopower Lockbox 3.
a) In DCPCrypt I have explicit control over the initialization vector. How would I set the IV in TPLB3?
b) DCPCrypt has no padding, we pad the plaintext with zeroes before encryption. How does TPLB pad? We could still do it ourselves of course.
Thanks Jan
a) IV
Let me preface by saying you may be trying to solve a problem that doesn't need solving. Lockbox 3 is auto-salted. That means that under most circumstances a 64 bit nonce is automatically generated and inserted into the IV. The nonce value is transported by means of insertion into the ciphertext stream. The upshot is that you can use the TCodec component without writing single line of code to manage IV's, and you still get all the cryptographic benefits of salting (basically meaning unpredictable IV's). This is in contrast to DCPCrypt, where you either have zeroised IV's or you self-manage the IV's.
I can't imagine a scenario, other than "Known Test Answer" testing that you would want or need to override this behaviour, but having said that, if you really want to insist on setting your own IV's, if you have a cvs client, you can download revision 231 (not yet "stable release" status), and implement the OnSetIV() event handler of the TCodec component to set the IV to your custom value. As the IV is transmitted with the message, this step is not necessary upon decrypt.
Let me know if you want some demo code.
b) Padding (corrected from first post. Sorry for the error.)
It depends on the chaining method. When the standard stream-to-block adapter is used, termination is handled in the following cases.
Zero length messages are encrypted as zero length ciphertext.
For ECB mode Lockbox 3 uses ISO/IEC 9797-1 method 2 padding. ISO/IEC 9797-1 method 2 essentially is a pad of one byte with value $80 followed by as many zero bytes as required to reach the next block boundary.
No padding. No special termination handling is required.
No padding. Termination is handled by truncation.
No padding. Termination is handled by ciphertext stealing, which is "too cool for school"! If the message is too short for ciphertext stealing (less than 2 blocks), then it automatically switches to CFB-8 bit and treat as key-streaming.
LockBox 3 was never designed for interoperability with CSharp style user-managed IV and all-zero padding. (IMHO, this type of padding is problematic and should be eschewed).
The following code fragment demonstrates LockBox3 decrypting from the test vector given in the comments. It is assumed that the ciphertext stream is prepended with the full IV and that the encrypting codec uses (yucky) all-zero padding.
procedure TForm5.Button1Click(Sender: TObject);
const
Key: ansistring = #$33#$d4#$6c#$ff#$a1#$58#$53#$31#$94#$21#$4a#$91#$e7#$12#$fc#$2b +
#$45#$b5#$87#$07#$66#$75#$af#$fd#$91#$0e#$de#$ca#$5f#$41#$ac#$64;
Reference_Plaintext: ansistring = 'a_decent_text';
IV: ansistring = #$91#$7f#$e2#$26#$df#$83#$08#$f4#$d9#$6c#$33#$30#$47#$68#$35#$4a;
var
Stream, ReconStream: TStream;
Cipherb64: ansistring;
Recon_Plaintext: ansistring;
begin
Stream := TMemoryStream.Create;
Stream.WriteBuffer( Key[1], Length( Key));
Stream.Position := 0;
CryptographicLibrary1.RegisterStreamCipher( StreamToBlock_Adapter_CSharpVariant);
Codec1.StreamCipherId := 'CSharp.StreamToBlock';
Codec1.BlockCipherId := Format( AES_ProgId, [256]);
Codec1.InitFromStream( Stream);
Stream.Size := 0;
Stream.WriteBuffer( IV[1], Length( IV));
Cipherb64 := '+kdTGzdV5KZIw8tv466nhQ==';
Base64_to_stream( Cipherb64, Stream);
ReconStream := TMemoryStream.Create;
Stream.Position := 0;
Codec1.DecryptStream( ReconStream, Stream);
ReconStream.Position := 0;
SetLength( Recon_Plaintext, ReconStream.Size);
ReconStream.ReadBuffer( Recon_Plaintext[1], Length( Recon_Plaintext));
SetLength( Recon_Plaintext, StrLen( PAnsiChar( Recon_Plaintext)));
ReconStream.Free;
Stream.Free;
if Recon_Plaintext = Reference_Plaintext then
ShowMessage( 'Test passed! LockBox3 decrypts from CSharp-style zero padding.')
else
ShowMessage( 'Test failed!')
end;
The maxiumum short message length, that is the say the maximum length of plaintext message that will be deemed as too short for classical ciphertext streaming, and so have it's chaining mode treated as a key-streaming one (CFB 8-bit), is one byte less than one block, (not 'less than 2 blocks' as stated earlier). A one and a half block message can still use ciphertext stealing for its block quantisation method. A half block message cannot.