问题
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.
Test Vector
- Cipher = AES-256;
- Chaining mode = CBC;
- Termination = C# style all-zero-padding;
- IV transmission = Full block prepended in the clear in the ciphertext stream.
- Key = 33d46cffa158533194214a91e712fc2b45b587076675affd910edeca5f41ac64 little-endien
- IV = 917fe226df8308f4d96c33304768354a
- Ciphertext = +kdTGzdV5KZIw8tv466nhQ== (base64)
- Plaintext = 'a_decent_text' (ansistring)
Thanks Jan
回答1:
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:
Zero length messages are encrypted as zero length ciphertext.
- ECB mode:
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.
- Not ECB, but message is block aligned:
No padding. No special termination handling is required.
- Key-streaming mode (such as OFB)
No padding. Termination is handled by truncation.
- Other (such as CBC)
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.
UPDATE
Caveat
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;
Some points to note:
- It is assumed that you have pre-created a TCodec and TCryptographicLibrary (suggestively named), probably on a form at design time.
- The TCodec's chaining mode and other properties have already been set at design time. In the case of our test vector, it should be set to CBC .
- The given stream-to-block adapter is a special one, not normally included in the cryptographic library. This is why there is a line of code to explicitly register it.
- You will need a CVS client to down-load the latest revision from the TurboPower LockBox 3 CVS repository. This adapter is not yet in the official stable release.
- Using this adapter, you can only decrypt. CSharp-compatible encryption is not yet available. (Let me know if you need it sooner rather than later).
- I tested it on Delphi 2007 and Delphi 2010. It works for me.
Correction
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.
来源:https://stackoverflow.com/questions/10847759/turbopower-lockbox3-can-i-control-initialization-vector-and-padding-for-aes-25