diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2016-04-20 19:48:32 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2016-04-20 19:48:32 +0700 |
commit | 27ce448162521ace7bc4c0520458ee3dd5665f53 (patch) | |
tree | 83153c6fb753ff5b24f53bf3496b0d9af0286350 /crypto/src | |
parent | Put zero-length extensions first in the ClientHello (diff) | |
download | BouncyCastle.NET-ed25519-27ce448162521ace7bc4c0520458ee3dd5665f53.tar.xz |
Update Poly1305 to comply with RFC 7539
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/crypto/generators/Poly1305KeyGenerator.cs | 65 | ||||
-rw-r--r-- | crypto/src/crypto/macs/Poly1305.cs | 76 | ||||
-rw-r--r-- | crypto/src/crypto/tls/Chacha20Poly1305.cs | 5 |
3 files changed, 58 insertions, 88 deletions
diff --git a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs index d05af0add..cdb24bfa0 100644 --- a/crypto/src/crypto/generators/Poly1305KeyGenerator.cs +++ b/crypto/src/crypto/generators/Poly1305KeyGenerator.cs @@ -66,51 +66,25 @@ namespace Org.BouncyCastle.Crypto.Generators * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl. */ if (key.Length != 32) - { throw new ArgumentException("Poly1305 key must be 256 bits."); - } - /* + /* * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15}) */ - key[19] &= R_MASK_HIGH_4; - key[23] &= R_MASK_HIGH_4; - key[27] &= R_MASK_HIGH_4; - key[31] &= R_MASK_HIGH_4; + key[3] &= R_MASK_HIGH_4; + key[7] &= R_MASK_HIGH_4; + key[11] &= R_MASK_HIGH_4; + key[15] &= R_MASK_HIGH_4; /* * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}). */ - key[20] &= R_MASK_LOW_2; - key[24] &= R_MASK_LOW_2; - key[28] &= R_MASK_LOW_2; + key[4] &= R_MASK_LOW_2; + key[8] &= R_MASK_LOW_2; + key[12] &= R_MASK_LOW_2; } - internal static void Clamp(byte[] key, int keyOff) - { - /* - * Key is k[0] ... k[15], r[0] ... r[15] as per poly1305_aes_clamp in ref impl. - */ - if (key.Length - 32 < keyOff) - throw new ArgumentException("Poly1305 key must be 256 bits."); - - /* - * r[3], r[7], r[11], r[15] have top four bits clear (i.e., are {0, 1, . . . , 15}) - */ - key[keyOff + 19] &= R_MASK_HIGH_4; - key[keyOff + 23] &= R_MASK_HIGH_4; - key[keyOff + 27] &= R_MASK_HIGH_4; - key[keyOff + 31] &= R_MASK_HIGH_4; - - /* - * r[4], r[8], r[12] have bottom two bits clear (i.e., are in {0, 4, 8, . . . , 252}). - */ - key[keyOff + 20] &= R_MASK_LOW_2; - key[keyOff + 24] &= R_MASK_LOW_2; - key[keyOff + 28] &= R_MASK_LOW_2; - } - - /// <summary> + /// <summary> /// Checks a 32 byte key for compliance with the Poly1305 key requirements, e.g. /// <code>k[0] ... k[15], r[0] ... r[15]</code> with the required bits in <code>r</code> cleared /// as per <see cref="Clamp(byte[])"/>. @@ -121,27 +95,22 @@ namespace Org.BouncyCastle.Crypto.Generators public static void CheckKey(byte[] key) { if (key.Length != 32) - { throw new ArgumentException("Poly1305 key must be 256 bits."); - } - checkMask(key[19], R_MASK_HIGH_4); - checkMask(key[23], R_MASK_HIGH_4); - checkMask(key[27], R_MASK_HIGH_4); - checkMask(key[31], R_MASK_HIGH_4); + CheckMask(key[3], R_MASK_HIGH_4); + CheckMask(key[7], R_MASK_HIGH_4); + CheckMask(key[11], R_MASK_HIGH_4); + CheckMask(key[15], R_MASK_HIGH_4); - checkMask(key[20], R_MASK_LOW_2); - checkMask(key[24], R_MASK_LOW_2); - checkMask(key[28], R_MASK_LOW_2); + CheckMask(key[4], R_MASK_LOW_2); + CheckMask(key[8], R_MASK_LOW_2); + CheckMask(key[12], R_MASK_LOW_2); } - private static void checkMask(byte b, byte mask) + private static void CheckMask(byte b, byte mask) { if ((b & (~mask)) != 0) - { throw new ArgumentException("Invalid format for r portion of Poly1305 key."); - } } - } } \ No newline at end of file diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs index 1a951ca04..0f66ccccc 100644 --- a/crypto/src/crypto/macs/Poly1305.cs +++ b/crypto/src/crypto/macs/Poly1305.cs @@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Crypto.Macs public class Poly1305 : IMac { - private const int BLOCK_SIZE = 16; + private const int BlockSize = 16; private readonly IBlockCipher cipher; @@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Crypto.Macs // Accumulating state /** Current block of buffered input */ - private byte[] currentBlock = new byte[BLOCK_SIZE]; + private byte[] currentBlock = new byte[BlockSize]; /** Current offset in input buffer */ private int currentBlockOffset = 0; @@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Crypto.Macs */ public Poly1305(IBlockCipher cipher) { - if (cipher.GetBlockSize() != BLOCK_SIZE) + if (cipher.GetBlockSize() != BlockSize) { throw new ArgumentException("Poly1305 requires a 128 bit block cipher."); } @@ -102,22 +102,24 @@ namespace Org.BouncyCastle.Crypto.Macs private void SetKey(byte[] key, byte[] nonce) { - if (cipher != null && (nonce == null || nonce.Length != BLOCK_SIZE)) - throw new ArgumentException("Poly1305 requires a 128 bit IV."); + if (key.Length != 32) + throw new ArgumentException("Poly1305 key must be 256 bits."); - Poly1305KeyGenerator.CheckKey(key); + if (cipher != null && (nonce == null || nonce.Length != BlockSize)) + throw new ArgumentException("Poly1305 requires a 128 bit IV."); - // Extract r portion of key - uint t0 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 0); - uint t1 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 4); - uint t2 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 8); - uint t3 = Pack.LE_To_UInt32(key, BLOCK_SIZE + 12); + // Extract r portion of key (and "clamp" the values) + uint t0 = Pack.LE_To_UInt32(key, 0); + uint t1 = Pack.LE_To_UInt32(key, 4); + uint t2 = Pack.LE_To_UInt32(key, 8); + uint t3 = Pack.LE_To_UInt32(key, 12); - r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; - r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; - r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; - r3 = t2 & 0x3f03fff; t3 >>= 8; - r4 = t3 & 0x00fffff; + // NOTE: The masks perform the key "clamping" implicitly + r0 = t0 & 0x03FFFFFFU; + r1 = ((t0 >> 26) | (t1 << 6)) & 0x03FFFF03U; + r2 = ((t1 >> 20) | (t2 << 12)) & 0x03FFC0FFU; + r3 = ((t2 >> 14) | (t3 << 18)) & 0x03F03FFFU; + r4 = (t3 >> 8) & 0x000FFFFFU; // Precompute multipliers s1 = r1 * 5; @@ -126,22 +128,27 @@ namespace Org.BouncyCastle.Crypto.Macs s4 = r4 * 5; byte[] kBytes; + int kOff; + if (cipher == null) { kBytes = key; + kOff = BlockSize; } else { // Compute encrypted nonce - kBytes = new byte[BLOCK_SIZE]; - cipher.Init(true, new KeyParameter(key, 0, BLOCK_SIZE)); + kBytes = new byte[BlockSize]; + kOff = 0; + + cipher.Init(true, new KeyParameter(key, BlockSize, BlockSize)); cipher.ProcessBlock(nonce, 0, kBytes, 0); } - k0 = Pack.LE_To_UInt32(kBytes, 0); - k1 = Pack.LE_To_UInt32(kBytes, 4); - k2 = Pack.LE_To_UInt32(kBytes, 8); - k3 = Pack.LE_To_UInt32(kBytes, 12); + k0 = Pack.LE_To_UInt32(kBytes, kOff + 0); + k1 = Pack.LE_To_UInt32(kBytes, kOff + 4); + k2 = Pack.LE_To_UInt32(kBytes, kOff + 8); + k3 = Pack.LE_To_UInt32(kBytes, kOff + 12); } public string AlgorithmName @@ -151,7 +158,7 @@ namespace Org.BouncyCastle.Crypto.Macs public int GetMacSize() { - return BLOCK_SIZE; + return BlockSize; } public void Update(byte input) @@ -165,13 +172,13 @@ namespace Org.BouncyCastle.Crypto.Macs int copied = 0; while (len > copied) { - if (currentBlockOffset == BLOCK_SIZE) + if (currentBlockOffset == BlockSize) { - processBlock(); + ProcessBlock(); currentBlockOffset = 0; } - int toCopy = System.Math.Min((len - copied), BLOCK_SIZE - currentBlockOffset); + int toCopy = System.Math.Min((len - copied), BlockSize - currentBlockOffset); Array.Copy(input, copied + inOff, currentBlock, currentBlockOffset, toCopy); copied += toCopy; currentBlockOffset += toCopy; @@ -179,12 +186,12 @@ namespace Org.BouncyCastle.Crypto.Macs } - private void processBlock() + private void ProcessBlock() { - if (currentBlockOffset < BLOCK_SIZE) + if (currentBlockOffset < BlockSize) { currentBlock[currentBlockOffset] = 1; - for (int i = currentBlockOffset + 1; i < BLOCK_SIZE; i++) + for (int i = currentBlockOffset + 1; i < BlockSize; i++) { currentBlock[i] = 0; } @@ -201,7 +208,7 @@ namespace Org.BouncyCastle.Crypto.Macs h3 += (uint)((((t3 << 32) | t2) >> 14) & 0x3ffffff); h4 += (uint)(t3 >> 8); - if (currentBlockOffset == BLOCK_SIZE) + if (currentBlockOffset == BlockSize) { h4 += (1 << 24); } @@ -223,15 +230,12 @@ namespace Org.BouncyCastle.Crypto.Macs public int DoFinal(byte[] output, int outOff) { - if (outOff + BLOCK_SIZE > output.Length) - { - throw new DataLengthException("Output buffer is too short."); - } + Check.DataLength(output, outOff, BlockSize, "Output buffer is too short."); if (currentBlockOffset > 0) { // Process padded block - processBlock(); + ProcessBlock(); } ulong f0, f1, f2, f3; @@ -273,7 +277,7 @@ namespace Org.BouncyCastle.Crypto.Macs Pack.UInt32_To_LE((uint)f3, output, outOff + 12); Reset(); - return BLOCK_SIZE; + return BlockSize; } public void Reset() diff --git a/crypto/src/crypto/tls/Chacha20Poly1305.cs b/crypto/src/crypto/tls/Chacha20Poly1305.cs index 817e64b25..8687803b4 100644 --- a/crypto/src/crypto/tls/Chacha20Poly1305.cs +++ b/crypto/src/crypto/tls/Chacha20Poly1305.cs @@ -145,10 +145,7 @@ namespace Org.BouncyCastle.Crypto.Tls byte[] firstBlock = new byte[64]; cipher.ProcessBytes(firstBlock, 0, firstBlock.Length, firstBlock, 0); - // NOTE: The BC implementation puts 'r' after 'k' - Array.Copy(firstBlock, 0, firstBlock, 32, 16); - Poly1305KeyGenerator.Clamp(firstBlock, 16); - KeyParameter macKey = new KeyParameter(firstBlock, 16, 32); + KeyParameter macKey = new KeyParameter(firstBlock, 0, 32); Arrays.Fill(firstBlock, (byte)0); return macKey; } |