YOUSEFUL / DELPHI / COMPONENTS
TAtlasSecretBox
Seal and open bytes or text with a 32-byte key or a password, using AES-256-GCM with generated nonces and salts.
Description
The class most applications should use for values that fit in memory. One call seals, one call opens; opening either returns exactly what was sealed or raises EAtlasCryptoError. Every nonce and salt is drawn from the system random generator and stored in the box, so sealing the same data twice gives different boxes.
Formats (integers big-endian):
- Key box
ASB1: magic (4) nonce (12) ciphertext tag (16); 32 bytes of overhead. - Password box
ASP1: magic (4) iterations (4) salt (16) nonce (12) ciphertext tag (16); 52 bytes of overhead. The key is PBKDF2-HMAC-SHA256 of the UTF-8 password.
The header is authenticated with the data, so changing the iteration count or salt breaks the tag, and every single byte of a box is protected. A Context value is authenticated but not stored: use it to tie a box to a record id or purpose so it cannot be moved elsewhere. Every failure to open raises the same message, Decryption failed: wrong key or password, or the data was altered.
These are Atlas Crypto's own formats. Another implementation can read them from the description above, but no interoperability test has been made.
Members
| Member | Kind | What it does |
|---|---|---|
KeySize | field | The key length in bytes (AES-256). |
MaxIterations | field | The most PBKDF2 rounds a password box may ask for. |
NewKey | method | Returns a new random 32-byte key. |
Seal | method | Returns an ASB1 box of Plain under Key, 32 bytes longer than Plain. |
Open | method | Returns the sealed bytes when Key and Context are the ones used to seal and the box is unaltered. |
SealWithPassword | method | Returns an ASP1 box of Plain, 52 bytes longer than Plain, with a key derived from Password and a fresh 16-byte salt. |
OpenWithPassword | method | Returns the sealed bytes of an ASP1 box. |
SealText | method | Seals the UTF-8 encoding of Text with Password and returns the box as URL-safe base64, ready for a text column, a configuration file or a URL. |
OpenText | method | Returns the text sealed by SealText. |
Methods
NewKey method
class function NewKey: TBytes; static;Returns a new random 32-byte key. Keep it in protected storage and Wipe it after use.
Key := TAtlasSecretBox.NewKey;Seal method
class function Seal(const Key, Plain: TBytes; const Context: TBytes = nil): TBytes; static;Returns an ASB1 box of Plain under Key, 32 bytes longer than Plain. Plain may be empty. A key that is not 32 bytes raises EAtlasCryptoError.
Box := TAtlasSecretBox.Seal(Key, Plain, TAtlasBytes.OfString('invoice:1042'));Open method
class function Open(const Key, Box: TBytes; const Context: TBytes = nil): TBytes; static;Returns the sealed bytes when Key and Context are the ones used to seal and the box is unaltered. Otherwise raises EAtlasCryptoError with the single decryption message. A key that is not 32 bytes raises its own message.
Plain := TAtlasSecretBox.Open(Key, Box, TAtlasBytes.OfString('invoice:1042'));SealWithPassword method
class function SealWithPassword(const Password: string; const Plain: TBytes; Iterations: Integer = TAtlasKdf.DefaultPasswordIterations): TBytes; static;Returns an ASP1 box of Plain, 52 bytes longer than Plain, with a key derived from Password and a fresh 16-byte salt. An empty password, or Iterations outside 1 to 20,000,000, raises EAtlasCryptoError. Lower counts are for tests only.
Box := TAtlasSecretBox.SealWithPassword(Password, Plain);OpenWithPassword method
class function OpenWithPassword(const Password: string; const Box: TBytes): TBytes; static;Returns the sealed bytes of an ASP1 box. The iteration count and salt come from the box. Passwords are case sensitive. Any failure raises the single decryption message.
Plain := TAtlasSecretBox.OpenWithPassword(Password, Box);SealText method
class function SealText(const Password, Text: string; Iterations: Integer = TAtlasKdf.DefaultPasswordIterations): string; static;Seals the UTF-8 encoding of Text with Password and returns the box as URL-safe base64, ready for a text column, a configuration file or a URL. Password first, text second.
Sealed := TAtlasSecretBox.SealText(Password, 'my note');OpenText method
class function OpenText(const Password, Sealed: string): string; static;Returns the text sealed by SealText. White space before and after Sealed is ignored; text that is not URL-safe base64 fails like any other bad box.
Text := TAtlasSecretBox.OpenText(Password, Sealed);Fields
KeySize field
const KeySize = 32;The key length in bytes (AES-256). Seal, Open and the key functions of TAtlasStreamCrypt refuse other lengths.
MaxIterations field
const MaxIterations = 20000000;The most PBKDF2 rounds a password box may ask for. Opening refuses a larger count, read from the untrusted header, before doing any work, so a forged box cannot tie up the process; sealing refuses it too.
Examples
Seal with a key and a context, then with a password
Prints 42 (10 bytes plus 32), TRUE, record 7 moved: refused, and pin 4712.
uses System.SysUtils, Atlas.Crypto, Atlas.CryptoBox;
procedure BoxesTwoWays;
var
Key, Box: TBytes;
Sealed: string;
begin
Key := TAtlasSecretBox.NewKey;
Box := TAtlasSecretBox.Seal(Key, TAtlasBytes.OfString('0123456789'), TAtlasBytes.OfString('record 7'));
WriteLn(Length(Box));
WriteLn(TEncoding.UTF8.GetString(TAtlasSecretBox.Open(Key, Box, TAtlasBytes.OfString('record 7'))) = '0123456789');
try
TAtlasSecretBox.Open(Key, Box, TAtlasBytes.OfString('record 8'));
except
on EAtlasCryptoError do WriteLn('record 7 moved: refused');
end;
TAtlasBytes.Wipe(Key);
Sealed := TAtlasSecretBox.SealText('a long pass phrase', 'pin 4712');
WriteLn(TAtlasSecretBox.OpenText('a long pass phrase', Sealed));
end;
Related
TAtlasStreamCrypt · TAtlasFileProtector · TAtlasAesGcm · TAtlasKdf · EAtlasCryptoError