The Magical Nonce: 24 bits, 64 bits or 192 bits?

--

In encryption, a nonce is a random value that is added to the plaintext before it is encrypted with a symmetric key. Thus, for the same plaintext and a different nonce value, we will generate a different ciphertext. It works beautifully. But what happens when the nonce value is too small? Well, with this, we basically take the cipher values with the same nonce value and can then easily crack the message. Here is the crack:

https://asecuritysite.com/stream/go_tink06

This short nonce value actually happened with the WEP wireless encryption method, and which used a 24-bit nonce — also known as an Initialization Vector (IV). With this, we started with a random 24-bit value and then incremented by 1 for each wireless packet. Eventually, the same IV came around again, and we basically just XORed the two cypher streams and then used statistical analysis on the result to decrypt back to plaintext. This works because WEP was based on RC4, and which is a stream cipher.

These days, we normally start with a 64-byte IV, such as for Sala20 [here]:

namespace Salsa20
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
class Program
{

static void Main(string[] args)
{



var msg="Hello";
var iv="0001020304050607";
var size=256;
if (args.Length >0) msg=args[0];
if (args.Length >1) iv=args[1];



try {
var plainTextData=System.Text.Encoding.UTF8.GetBytes(msg);
Salsa20Engine cipher = new Org.BouncyCastle.Crypto.Engines.Salsa20Engine();
byte[] nonce = new byte[8];
Array.Copy(Convert.FromHexString(iv), nonce, 8);

CipherKeyGenerator keyGen = new CipherKeyGenerator();
keyGen.Init(new KeyGenerationParameters(new SecureRandom(), size));
KeyParameter keyParam = keyGen.GenerateKeyParameter();

ParametersWithIV keys = new ParametersWithIV(keyParam,nonce,0,nonce.Length);
cipher.Init(true,keys);

byte[] cipherTextData = new byte[plainTextData.Length];
cipher.ProcessBytes(plainTextData, 0, plainTextData.Length, cipherTextData, 0);
var rtn = cipherTextData;

// Decrypt
cipher.Init(false,keys);
plainTextData = new byte[cipherTextData.Length];
cipher.ProcessBytes(cipherTextData, 0, cipherTextData.Length,plainTextData, 0);
var pln=plainTextData;
Console.WriteLine("==={0} Cipher ==",cipher.AlgorithmName);
Console.WriteLine("Message:\t\t{0}",msg);
Console.WriteLine("IV:\t\t\t{0}",iv);
Console.WriteLine("Key:\t\t\t{0} [{1}]",Convert.ToHexString(keyParam.GetKey()),Convert.ToBase64String(keyParam.GetKey()));
Console.WriteLine("\nCipher (hex):\t\t{0}",Convert.ToHexString(rtn));
Console.WriteLine("Cipher (Base64):\t{0}",Convert.ToBase64String(rtn));
Console.WriteLine("\nPlain:\t\t\t{0}",System.Text.Encoding.UTF8.GetString(pln));

} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}
}
}

}

For this we are using the an IV of “|0001020304050607”, and which is eight bytes (64 bits). A sample run is [here]:

===Salsa20 Cipher ==
Message: Hello 123
IV: 0001020304050607
Key: DFA1FAF23B7A8ED8C0229CE3E8F29AC875742E0FE4D229DD45B543AFAEB87B1E [36H68jt6jtjAIpzj6PKayHV0Lg/k0indRbVDr664ex4=]
Cipher (hex): 271EDAA4EDCBF00C36
Cipher (Base64): Jx7apO3L8Aw2
Plain: Hello 123

But, what if a 64-bit nonce is not secure enough? Well, for Sala20, we can use XSalsa20, and which has a 192-bit nonce value [here]:

namespace XSalsa20
{
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;

class Program
{

static void Main(string[] args)
{



var msg="Hello";
var iv="01020304050607000102030405060700010203040506070001020304050607";
var size=256;

if (args.Length >0) msg=args[0];

if (args.Length >1) iv=args[1];




try {

var plainTextData=System.Text.Encoding.UTF8.GetBytes(msg);

XSalsa20Engine cipher = new Org.BouncyCastle.Crypto.Engines.XSalsa20Engine();

byte[] nonce = new byte[24];
Array.Copy(Convert.FromHexString(iv), nonce, 24);


CipherKeyGenerator keyGen = new CipherKeyGenerator();
keyGen.Init(new KeyGenerationParameters(new SecureRandom(), size));
KeyParameter keyParam = keyGen.GenerateKeyParameter();


ParametersWithIV keys = new ParametersWithIV(keyParam,nonce,0,nonce.Length);

cipher.Init(true,keys);


byte[] cipherTextData = new byte[plainTextData.Length];
cipher.ProcessBytes(plainTextData, 0, plainTextData.Length, cipherTextData, 0);

var rtn = cipherTextData;


// Decrypt
cipher.Init(false,keys);

plainTextData = new byte[cipherTextData.Length];
cipher.ProcessBytes(cipherTextData, 0, cipherTextData.Length,plainTextData, 0);
var pln=plainTextData;

Console.WriteLine("==={0} Cipher ==",cipher.AlgorithmName);
Console.WriteLine("Message:\t\t{0}",msg);
Console.WriteLine("IV:\t\t\t{0}",iv);
Console.WriteLine("Key:\t\t\t{0} [{1}]",Convert.ToHexString(keyParam.GetKey()),Convert.ToBase64String(keyParam.GetKey()));

Console.WriteLine("\nCipher (hex):\t\t{0}",Convert.ToHexString(rtn));
Console.WriteLine("Cipher (Base64):\t{0}",Convert.ToBase64String(rtn));
Console.WriteLine("\nPlain:\t\t\t{0}",System.Text.Encoding.UTF8.GetString(pln));



} catch (Exception e) {
Console.WriteLine("Error: {0}",e.Message);
}
}
}



}

In this case we have an IV of “01020304050607000102030405060700010203040506070001020304050607”, and which is 24 bytes (192 bits). A sample run is [here]:

===XSalsa20 Cipher ==
Message: Hello 123
IV: 01020304050607000102030405060700010203040506070001020304050607
Key: 0B25834A9B5631C8BFA0F9896050B4CD4EF92F5A65C05CE525182543A7722648 [CyWDSptWMci/oPmJYFC0zU75L1plwFzlJRglQ6dyJkg=]

Cipher (hex): 6E0DC761680F3C3990
Cipher (Base64): bg3HYWgPPDmQ

Plain: Hello 123

Notice that the cipher stream is the same length as the plaintext stream. In this case we have nine bytes in the message, and have nine bytes in the ciphertext (“6E0DC761680F3C3990”).

--

--

Prof Bill Buchanan OBE FRSE
ASecuritySite: When Bob Met Alice

Professor of Cryptography. Serial innovator. Believer in fairness, justice & freedom. Based in Edinburgh. Old World Breaker. New World Creator. Building trust.