TStreamCipher

0

TForge 0.76 is released.

The release introduces a new class TStreamCipher. The name TStreamCipher does not mean that the class supports stream cipher algorithms only, such as Salsa20 or RC4 – it supports all cipher algorithms currently implemented in TForge, like TCipher class does; block ciphers are converted into stream ciphers using CTR mode of operation.

The initial motivation to write TStreamCipher class was to generate “solid” byte-wise keystream. TCipher class generates block-wise keystream; to obtain solid byte-wise keystream you need to maintain additional state, and that’s what the TStreamCipher class is doing. Here is the code sample illustrating the above:

const
  Nonce = 42;

var
  Cipher: TCipher;
  StreamCipher: TStreamCipher;
  Key: ByteArray;
  KeyStream, KeyStream1, KeyStream2: ByteArray;

begin
// create 128-bit AES key:
  Key:= ByteArray.AllocateRand(16);

// generate 16 bytes of keystream:
  KeyStream:= TCipher.AES.ExpandKey(Key, CTR_ENCRYPT, Nonce).KeyStream(16);
  Writeln(KeyStream.ToHex);

// generate 8 + 8 bytes of keystream:
  Cipher:= TCipher.AES.ExpandKey(Key, CTR_ENCRYPT, Nonce);
// Warning - KeyStream1:= Cipher.KeyStream(8) + Cipher.KeyStream(8) is wrong
//   because the compiler does not evaluate the summands in order
  KeyStream1:= Cipher.KeyStream(8);
  KeyStream1:= KeyStream1 + Cipher.KeyStream(8);
  Writeln(KeyStream1.ToHex);
  Assert(KeyStream <> KeyStream1);

// generate 8 + 8 bytes of keystream using TStreamCipher instance:
  StreamCipher:= TStreamCipher.AES.ExpandKey(Key, Nonce);
  KeyStream2:= StreamCipher.KeyStream(8);
  KeyStream2:= KeyStream2 + StreamCipher.KeyStream(8);
  Writeln(KeyStream2.ToHex);
  Assert(KeyStream = KeyStream2);
end;

The Cipher instance generates 8 + 8 bytes of keystream by taking the first 8 bytes from the first block and the second 8 bytes from the second block (AES block size is 16 bytes), that is why the generated keystream is different.

The code also illustrates the use of Nonce. The purpose of nonce is to encrypt multiple messages (ex files) with the same secret key – each message should be encrypted with unique non-secret nonce. Modern cryptoalgorithms such as Salsa20 have built-in support for nonce, and TForge supported the feature since version 0.71; old block cipher algorithms such as AES allow to implement the same feature using IV (initialization vector), and this is the second thing that TStreamCipher class is doing; TStreamCipher API does not expose IV of the underlying cryptoalgorithm, it exposes Nonce only.

Nonces are now supported by both TStreamCipher and TCipher classes, as the above code sample shows; there is a limitation though: the block size of an algorithm should be 128 bits at least; that means you can’t use nonces with legacy 64-bit block ciphers such as DES or Triple DES.

TForge 0.76 includes new demo project FileEncryptDemo (Demos\Ciphers folder) which shows how to use TStreamCipher. The idea of the project is to implement secure encryption of multiple files with a single key (and multiple non-secret nonces) and transparent reading of the encrypted files.

Advertisements

Serial Number System Challenge

6

I stumbled across an interesting link that made me think about a solid serial number system based on strong cryptography. Cryptography discourages systems based on secret algorithms, and relies on open algorithms and secret keys. So let us develop a serial number generation/verification system with the same usability as the one in the linked article but without any secret algorithms.


First, our serial numbers should have the form

XXXX-XXXX-XXXX-XXXX-XXXX

where X – an uppercase english letter A..Z; to prevent user’s confusion let us exclude the letter O which looks like zero, so in the end we have 25 possible letters in 20 positions, that is BigInteger.Pow(25, 20) = $1D6329F1C35CA4BFABB9F561 combinations. Next, we want to work with full bytes; this reduces the possible serial keys to 11 byte-long numbers; also we want to use 2 bytes of serial key as a key checksum; this leaves us with 9 bytes, and we have 9*8 = 72-bit serial keys. That should be strong enough against full keyspace search attack on our system.


Suppose you are a micro-ISV and expecting to sell up to 100 copies of you software; then you need to generate 100 72-bit keys and embed their hashes into the executable (if it will turn out later that you need more copies it is not a problem – just recompile your executable with more keys next time; the same way you can revoke leaked keys – by not including them in the next release).

To derive 72-bit keys I use 128-bit master key and AES encryption algorithm as a pseudorandom function. Note that the 128-bit master key is actually the only secret in the system, everything else is calculated. It is worthwhile to generate the master key, for example, by tossing a coin 128 times.

For hashing I use SHA256 hash function. I also use CRC16 algorithm to calculate the key checksums.


The verification is 2-phase process. First, it converts a serial number in 20-letter format entered by user into a 11-byte serial key, calculates the checksum of the first 9 bytes and compares it with the last 2 bytes (this prevents user from mistyping his serial number). Second, it hashes the 9-byte key and checks that the hash exists in the keyhash table.


And now the challenge. The last TForge release (0.74) includes full source code of console application with the serial number system described above, in the Demos\Challenge subfolder. The key generation code is also included, though it is not used in the application and could be kept secret; the only thing I keep secret is 128-bit master key used.

Build the application with Delphi or Lazarus/Free Pascal.

One of the valid serial numbers is:

AVVH-GJCX-YVWM-EHUE-YMRL

Try to find other valid serial number(s).

BigInteger redux

11

TForge 0.72 is released.

What’s new:

  • Big integer arithmetic is included in TForge package; that is BigCardinal and BigInteger classes are now available after installing TForge package, without dll. Old dll implementation (Numerics 0.58) is still available but is not developed for now.
  • More demo projects added.
  • Improved FPC/Lazarus support; TCiphers package and demos are ported to FPC/Lazarus.
  • Several new methods are added to ByteArray class.

More Ciphers

1

TForge 0.71 is released.

What’s new:

  • TCipher.Salsa20.SetNonce bug fixed
  • added 3DES block cipher algorithm
  • added ChaCha20 stream cipher algorithm

Examples of creating new cipher instances:

var
  Cipher: TCipher;

begin
  Cipher:= TCipher.TripleDES;   // 3DES
  Cipher:= TCipher.ChaCha20;    // 20-rounds ChaCha
  Cipher:= TCipher.ChaCha20(12) // 12-rounds ChaCha

ChaCha20 (aka ChaCha) is Salsa20 variant which is becoming popular after Google has selected ChaCha20 as a replacement for RC4 in communication protocols.

Salsa20 support explained

10

Salsa20 is a stream cipher; like any stream cipher Salsa20 encrypts/decrypts data by xor‘ing a plaintext/ciphertext with a pseudorandom keystream.

Salsa20 generates keystream by hashing 64-byte (512-bit) blocks; the block consists of 4 parts:

  • fixed “magic words” – 16 bytes
  • key – 32 bytes
  • nonce (message number) – 8 bytes
  • block number – 8 bytes

This simple structure allows to generate 64-byte blocks of keystream independently; to generate an arbitrary block of the keystream one need to set the block number in the cipher’s state and hash the 64-byte block.

TCipher class supports Salsa20 design by following methods:

function TCipher.SetIV(const AIV: ByteArray): TCipher;
function TCipher.SetNonce(Value: UInt64): TCipher;
function TCipher.Skip(Value: UInt64): TCipher;

TCipher class considers concatenated nonce and block number as initialization vector (IV). The TCipher.SetIV sets both the nonce and the block number in the cipher instance state. [Corrected – changed in ver 0.71]

The TCipher.SetIV  and TCipher.SetNonce methods do the same – set the nonce field in the the cipher instance state and clear the block number field; the difference is that TCipher.SetIV accepts the parameter as a byte array while TCipher.SetNonce as an integer.

The TCipher.SetIV method was introduced mainly for testing purposes.

The purpose of nonce is to serve as a unique message number; a nonce need not be kept secret, but it should never repeat during the lifetime of a secret key.

As an example suppose we want to encrypt several files by a single secret key; the right way to do it is to encrypt each file with a unique nonce value, like this:

procedure EncryptFiles(const Key: ByteArray; FileNames: array of string);
var
  Cipher: TCipher;
  Nonce: UInt64;
  I: Integer;

begin
  Nonce:= 0;
  for I:= 0 to High(FileNames) do begin
    Cipher:= TCipher.Salsa20;
    Inc(Nonce);
    try
      Cipher.ExpandKey(Key)
            .SetNonce(Nonce)
            .EncryptFile(FileNames[I], FileNames[I] + '.salsa20');
    finally
      Cipher.Burn;
    end;
  end;
end;

The try .. finally block ensures that the sensitive key data in the cipher instances’ states is destroyed.

The TCipher.Skip method increments the block number field in the cipher instance state; its purpose is to implement parallel encryption/decryption as was demonstrated in the previous post.