diff options
author | David Hook <dgh@bouncycastle.org> | 2016-12-28 22:02:41 +1100 |
---|---|---|
committer | David Hook <dgh@bouncycastle.org> | 2016-12-28 22:02:41 +1100 |
commit | d21cb9eeb630b0b81978a907c08cc88cdd650cd7 (patch) | |
tree | adffc74ed7019ef8cf89691960ff211b88f6c3d2 /crypto/src | |
parent | fixed head of loop to use primitive type. (diff) | |
parent | Fix carry propagation bug in Nat???.Square methods (diff) | |
download | BouncyCastle.NET-ed25519-d21cb9eeb630b0b81978a907c08cc88cdd650cd7.tar.xz |
Merge branch 'master' of bcgit@git.bouncycastle.org:bc-csharp.git
Diffstat (limited to 'crypto/src')
43 files changed, 787 insertions, 273 deletions
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs index a3c2cee01..26adc575b 100644 --- a/crypto/src/asn1/DerBitString.cs +++ b/crypto/src/asn1/DerBitString.cs @@ -28,6 +28,17 @@ namespace Org.BouncyCastle.Asn1 { return (DerBitString) obj; } + if (obj is byte[]) + { + try + { + return (DerBitString)FromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new ArgumentException("encoding error in GetInstance: " + e.ToString()); + } + } throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj)); } diff --git a/crypto/src/asn1/ocsp/CertStatus.cs b/crypto/src/asn1/ocsp/CertStatus.cs index b524364c9..7dd99b844 100644 --- a/crypto/src/asn1/ocsp/CertStatus.cs +++ b/crypto/src/asn1/ocsp/CertStatus.cs @@ -48,6 +48,8 @@ namespace Org.BouncyCastle.Asn1.Ocsp case 2: value = DerNull.Instance; break; + default: + throw new ArgumentException("Unknown tag encountered: " + choice.TagNo); } } diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs index c33f16f78..ca7b3fa3f 100644 --- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs @@ -46,6 +46,9 @@ namespace Org.BouncyCastle.Crypto.Agreement ICipherParameters pubKey) { ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey; + if (!pub.Parameters.Equals(privKey.Parameters)) + throw new InvalidOperationException("ECDH public key has wrong domain parameters"); + ECPoint P = pub.Q.Multiply(privKey.D).Normalize(); if (P.IsInfinity) diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs index 89be7061e..1c9ae45f9 100644 --- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs @@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Crypto.Agreement public class ECDHCBasicAgreement : IBasicAgreement { - private ECPrivateKeyParameters key; + private ECPrivateKeyParameters privKey; public virtual void Init( ICipherParameters parameters) @@ -39,12 +39,12 @@ namespace Org.BouncyCastle.Crypto.Agreement parameters = ((ParametersWithRandom) parameters).Parameters; } - this.key = (ECPrivateKeyParameters)parameters; + this.privKey = (ECPrivateKeyParameters)parameters; } public virtual int GetFieldSize() { - return (key.Parameters.Curve.FieldSize + 7) / 8; + return (privKey.Parameters.Curve.FieldSize + 7) / 8; } public virtual BigInteger CalculateAgreement( @@ -52,8 +52,10 @@ namespace Org.BouncyCastle.Crypto.Agreement { ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey; ECDomainParameters parameters = pub.Parameters; + if (!parameters.Equals(privKey.Parameters)) + throw new InvalidOperationException("ECDHC public key has wrong domain parameters"); - BigInteger hd = parameters.H.Multiply(key.D).Mod(parameters.N); + BigInteger hd = parameters.H.Multiply(privKey.D).Mod(parameters.N); ECPoint P = pub.Q.Multiply(hd).Normalize(); diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs index f55ae46af..8d5cebb13 100644 --- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs @@ -34,8 +34,12 @@ namespace Org.BouncyCastle.Crypto.Agreement MqvPublicParameters pubParams = (MqvPublicParameters)pubKey; ECPrivateKeyParameters staticPrivateKey = privParams.StaticPrivateKey; + ECDomainParameters parameters = staticPrivateKey.Parameters; - ECPoint agreement = CalculateMqvAgreement(staticPrivateKey.Parameters, staticPrivateKey, + if (!parameters.Equals(pubParams.StaticPublicKey.Parameters)) + throw new InvalidOperationException("ECMQV public key components have wrong domain parameters"); + + ECPoint agreement = CalculateMqvAgreement(parameters, staticPrivateKey, privParams.EphemeralPrivateKey, privParams.EphemeralPublicKey, pubParams.StaticPublicKey, pubParams.EphemeralPublicKey).Normalize(); @@ -61,8 +65,8 @@ namespace Org.BouncyCastle.Crypto.Agreement ECCurve curve = parameters.Curve; ECPoint[] points = new ECPoint[]{ - // The Q2U public key is optional - ECAlgorithms.ImportPoint(curve, Q2U == null ? parameters.G.Multiply(d2U.D) : Q2U.Q), + // The Q2U public key is optional - but will be calculated for us if it wasn't present + ECAlgorithms.ImportPoint(curve, Q2U.Q), ECAlgorithms.ImportPoint(curve, Q1V.Q), ECAlgorithms.ImportPoint(curve, Q2V.Q) }; diff --git a/crypto/src/crypto/generators/BCrypt.cs b/crypto/src/crypto/generators/BCrypt.cs index b21a8671f..af8029a1b 100644 --- a/crypto/src/crypto/generators/BCrypt.cs +++ b/crypto/src/crypto/generators/BCrypt.cs @@ -14,8 +14,8 @@ namespace Org.BouncyCastle.Crypto.Generators * "A Future-Adaptable Password Scheme" of Niels Provos and David Mazières, * see: https://www.usenix.org/legacy/events/usenix99/provos/provos_html/node1.html. * In contrast to the paper, the order of key setup and salt setup is reversed: - * state <- ExpandKey(state, 0, key) - * state <- ExpandKey(state, 0, salt) + * state <- ExpandKey(state, 0, key) + * state %lt;- ExpandKey(state, 0, salt) * This corresponds to the OpenBSD reference implementation of Bcrypt. * </p><p> * Note: diff --git a/crypto/src/crypto/generators/HKDFBytesGenerator.cs b/crypto/src/crypto/generators/HKDFBytesGenerator.cs new file mode 100644 index 000000000..c2e667c95 --- /dev/null +++ b/crypto/src/crypto/generators/HKDFBytesGenerator.cs @@ -0,0 +1,153 @@ +using System; + +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Generators +{ + /** + * HMAC-based Extract-and-Expand Key Derivation Function (HKDF) implemented + * according to IETF RFC 5869, May 2010 as specified by H. Krawczyk, IBM + * Research & P. Eronen, Nokia. It uses a HMac internally to compute de OKM + * (output keying material) and is likely to have better security properties + * than KDF's based on just a hash function. + */ + public class HkdfBytesGenerator + : IDerivationFunction + { + private HMac hMacHash; + private int hashLen; + + private byte[] info; + private byte[] currentT; + + private int generatedBytes; + + /** + * Creates a HKDFBytesGenerator based on the given hash function. + * + * @param hash the digest to be used as the source of generatedBytes bytes + */ + public HkdfBytesGenerator(IDigest hash) + { + this.hMacHash = new HMac(hash); + this.hashLen = hash.GetDigestSize(); + } + + public virtual void Init(IDerivationParameters parameters) + { + if (!(parameters is HkdfParameters)) + throw new ArgumentException("HKDF parameters required for HkdfBytesGenerator", "parameters"); + + HkdfParameters hkdfParameters = (HkdfParameters)parameters; + if (hkdfParameters.SkipExtract) + { + // use IKM directly as PRK + hMacHash.Init(new KeyParameter(hkdfParameters.GetIkm())); + } + else + { + hMacHash.Init(Extract(hkdfParameters.GetSalt(), hkdfParameters.GetIkm())); + } + + info = hkdfParameters.GetInfo(); + + generatedBytes = 0; + currentT = new byte[hashLen]; + } + + /** + * Performs the extract part of the key derivation function. + * + * @param salt the salt to use + * @param ikm the input keying material + * @return the PRK as KeyParameter + */ + private KeyParameter Extract(byte[] salt, byte[] ikm) + { + hMacHash.Init(new KeyParameter(ikm)); + if (salt == null) + { + // TODO check if hashLen is indeed same as HMAC size + hMacHash.Init(new KeyParameter(new byte[hashLen])); + } + else + { + hMacHash.Init(new KeyParameter(salt)); + } + + hMacHash.BlockUpdate(ikm, 0, ikm.Length); + + byte[] prk = new byte[hashLen]; + hMacHash.DoFinal(prk, 0); + return new KeyParameter(prk); + } + + /** + * Performs the expand part of the key derivation function, using currentT + * as input and output buffer. + * + * @throws DataLengthException if the total number of bytes generated is larger than the one + * specified by RFC 5869 (255 * HashLen) + */ + private void ExpandNext() + { + int n = generatedBytes / hashLen + 1; + if (n >= 256) + { + throw new DataLengthException( + "HKDF cannot generate more than 255 blocks of HashLen size"); + } + // special case for T(0): T(0) is empty, so no update + if (generatedBytes != 0) + { + hMacHash.BlockUpdate(currentT, 0, hashLen); + } + hMacHash.BlockUpdate(info, 0, info.Length); + hMacHash.Update((byte)n); + hMacHash.DoFinal(currentT, 0); + } + + public virtual IDigest Digest + { + get { return hMacHash.GetUnderlyingDigest(); } + } + + public virtual int GenerateBytes(byte[] output, int outOff, int len) + { + if (generatedBytes + len > 255 * hashLen) + { + throw new DataLengthException( + "HKDF may only be used for 255 * HashLen bytes of output"); + } + + if (generatedBytes % hashLen == 0) + { + ExpandNext(); + } + + // copy what is left in the currentT (1..hash + int toGenerate = len; + int posInT = generatedBytes % hashLen; + int leftInT = hashLen - generatedBytes % hashLen; + int toCopy = System.Math.Min(leftInT, toGenerate); + Array.Copy(currentT, posInT, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + + while (toGenerate > 0) + { + ExpandNext(); + toCopy = System.Math.Min(hashLen, toGenerate); + Array.Copy(currentT, 0, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } + + return len; + } + } +} diff --git a/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs index cbbfd1b3b..85543a038 100644 --- a/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs +++ b/crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs @@ -163,7 +163,6 @@ namespace Org.BouncyCastle.Crypto.Generators * @param keySize the size of the key we want (in bits) * @return a KeyParameter object. */ - [Obsolete("Use version with 'algorithm' parameter")] public override ICipherParameters GenerateDerivedParameters( int keySize) { @@ -194,7 +193,6 @@ namespace Org.BouncyCastle.Crypto.Generators * @param ivSize the size of the iv we want (in bits) * @return a ParametersWithIV object. */ - [Obsolete("Use version with 'algorithm' parameter")] public override ICipherParameters GenerateDerivedParameters( int keySize, int ivSize) diff --git a/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs index 8586e1ca9..9b39a5f42 100644 --- a/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs +++ b/crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs @@ -62,7 +62,6 @@ namespace Org.BouncyCastle.Crypto.Generators * @return a KeyParameter object. * @exception ArgumentException if the key length larger than the base hash size. */ - [Obsolete("Use version with 'algorithm' parameter")] public override ICipherParameters GenerateDerivedParameters( int keySize) { @@ -96,7 +95,6 @@ namespace Org.BouncyCastle.Crypto.Generators * @return a ParametersWithIV object. * @exception ArgumentException if keySize + ivSize is larger than the base hash size. */ - [Obsolete("Use version with 'algorithm' parameter")] public override ICipherParameters GenerateDerivedParameters( int keySize, int ivSize) diff --git a/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs b/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs index 10352abbc..0b0caa057 100644 --- a/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs +++ b/crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs @@ -106,7 +106,6 @@ namespace Org.BouncyCastle.Crypto.Generators * @param keySize the size of the key we want (in bits) * @return a KeyParameter object. */ - [Obsolete("Use version with 'algorithm' parameter")] public override ICipherParameters GenerateDerivedParameters( int keySize) { @@ -133,7 +132,6 @@ namespace Org.BouncyCastle.Crypto.Generators * @param ivSize the size of the iv we want (in bits) * @return a ParametersWithIV object. */ - [Obsolete("Use version with 'algorithm' parameter")] public override ICipherParameters GenerateDerivedParameters( int keySize, int ivSize) 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/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs index 4258df5c5..bdea12432 100644 --- a/crypto/src/crypto/parameters/DHParameters.cs +++ b/crypto/src/crypto/parameters/DHParameters.cs @@ -162,7 +162,7 @@ namespace Org.BouncyCastle.Crypto.Parameters return Equals(other); } - protected bool Equals( + protected virtual bool Equals( DHParameters other) { return p.Equals(other.p) diff --git a/crypto/src/crypto/parameters/ECDomainParameters.cs b/crypto/src/crypto/parameters/ECDomainParameters.cs index 619971a6c..732fbdfa4 100644 --- a/crypto/src/crypto/parameters/ECDomainParameters.cs +++ b/crypto/src/crypto/parameters/ECDomainParameters.cs @@ -93,24 +93,25 @@ namespace Org.BouncyCastle.Crypto.Parameters return Equals(other); } - protected bool Equals( + protected virtual bool Equals( ECDomainParameters other) { return curve.Equals(other.curve) && g.Equals(other.g) && n.Equals(other.n) - && h.Equals(other.h) - && Arrays.AreEqual(seed, other.seed); + && h.Equals(other.h); } public override int GetHashCode() { - return curve.GetHashCode() - ^ g.GetHashCode() - ^ n.GetHashCode() - ^ h.GetHashCode() - ^ Arrays.GetHashCode(seed); + int hc = curve.GetHashCode(); + hc *= 37; + hc ^= g.GetHashCode(); + hc *= 37; + hc ^= n.GetHashCode(); + hc *= 37; + hc ^= h.GetHashCode(); + return hc; } } - } diff --git a/crypto/src/crypto/parameters/HKDFParameters.cs b/crypto/src/crypto/parameters/HKDFParameters.cs new file mode 100644 index 000000000..6d1465e4c --- /dev/null +++ b/crypto/src/crypto/parameters/HKDFParameters.cs @@ -0,0 +1,119 @@ +using System; + +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Parameters +{ + /** + * Parameter class for the HkdfBytesGenerator class. + */ + public class HkdfParameters + : IDerivationParameters + { + private readonly byte[] ikm; + private readonly bool skipExpand; + private readonly byte[] salt; + private readonly byte[] info; + + private HkdfParameters(byte[] ikm, bool skip, byte[] salt, byte[] info) + { + if (ikm == null) + throw new ArgumentNullException("ikm"); + + this.ikm = Arrays.Clone(ikm); + this.skipExpand = skip; + + if (salt == null || salt.Length == 0) + { + this.salt = null; + } + else + { + this.salt = Arrays.Clone(salt); + } + + if (info == null) + { + this.info = new byte[0]; + } + else + { + this.info = Arrays.Clone(info); + } + } + + /** + * Generates parameters for HKDF, specifying both the optional salt and + * optional info. Step 1: Extract won't be skipped. + * + * @param ikm the input keying material or seed + * @param salt the salt to use, may be null for a salt for hashLen zeros + * @param info the info to use, may be null for an info field of zero bytes + */ + public HkdfParameters(byte[] ikm, byte[] salt, byte[] info) + : this(ikm, false, salt, info) + { + } + + /** + * Factory method that makes the HKDF skip the extract part of the key + * derivation function. + * + * @param ikm the input keying material or seed, directly used for step 2: + * Expand + * @param info the info to use, may be null for an info field of zero bytes + * @return HKDFParameters that makes the implementation skip step 1 + */ + public static HkdfParameters SkipExtractParameters(byte[] ikm, byte[] info) + { + return new HkdfParameters(ikm, true, null, info); + } + + public static HkdfParameters DefaultParameters(byte[] ikm) + { + return new HkdfParameters(ikm, false, null, null); + } + + /** + * Returns the input keying material or seed. + * + * @return the keying material + */ + public virtual byte[] GetIkm() + { + return Arrays.Clone(ikm); + } + + /** + * Returns if step 1: extract has to be skipped or not + * + * @return true for skipping, false for no skipping of step 1 + */ + public virtual bool SkipExtract + { + get { return skipExpand; } + } + + /** + * Returns the salt, or null if the salt should be generated as a byte array + * of HashLen zeros. + * + * @return the salt, or null + */ + public virtual byte[] GetSalt() + { + return Arrays.Clone(salt); + } + + /** + * Returns the info field, which may be empty (null is converted to empty). + * + * @return the info field, never null + */ + public virtual byte[] GetInfo() + { + return Arrays.Clone(info); + } + } +} diff --git a/crypto/src/crypto/parameters/MqvPrivateParameters.cs b/crypto/src/crypto/parameters/MqvPrivateParameters.cs index 4bf33e347..9159cac12 100644 --- a/crypto/src/crypto/parameters/MqvPrivateParameters.cs +++ b/crypto/src/crypto/parameters/MqvPrivateParameters.cs @@ -21,22 +21,42 @@ namespace Org.BouncyCastle.Crypto.Parameters ECPrivateKeyParameters ephemeralPrivateKey, ECPublicKeyParameters ephemeralPublicKey) { - this.staticPrivateKey = staticPrivateKey; - this.ephemeralPrivateKey = ephemeralPrivateKey; - this.ephemeralPublicKey = ephemeralPublicKey; + if (staticPrivateKey == null) + throw new ArgumentNullException("staticPrivateKey"); + if (ephemeralPrivateKey == null) + throw new ArgumentNullException("ephemeralPrivateKey"); + + ECDomainParameters parameters = staticPrivateKey.Parameters; + if (!parameters.Equals(ephemeralPrivateKey.Parameters)) + throw new ArgumentException("Static and ephemeral private keys have different domain parameters"); + + if (ephemeralPublicKey == null) + { + ephemeralPublicKey = new ECPublicKeyParameters( + parameters.G.Multiply(ephemeralPrivateKey.D), + parameters); + } + else if (!parameters.Equals(ephemeralPublicKey.Parameters)) + { + throw new ArgumentException("Ephemeral public key has different domain parameters"); + } + + this.staticPrivateKey = staticPrivateKey; + this.ephemeralPrivateKey = ephemeralPrivateKey; + this.ephemeralPublicKey = ephemeralPublicKey; } - public ECPrivateKeyParameters StaticPrivateKey + public virtual ECPrivateKeyParameters StaticPrivateKey { get { return staticPrivateKey; } } - public ECPrivateKeyParameters EphemeralPrivateKey + public virtual ECPrivateKeyParameters EphemeralPrivateKey { get { return ephemeralPrivateKey; } } - public ECPublicKeyParameters EphemeralPublicKey + public virtual ECPublicKeyParameters EphemeralPublicKey { get { return ephemeralPublicKey; } } diff --git a/crypto/src/crypto/parameters/MqvPublicParameters.cs b/crypto/src/crypto/parameters/MqvPublicParameters.cs index a0e273ac4..239afa321 100644 --- a/crypto/src/crypto/parameters/MqvPublicParameters.cs +++ b/crypto/src/crypto/parameters/MqvPublicParameters.cs @@ -8,20 +8,27 @@ namespace Org.BouncyCastle.Crypto.Parameters private readonly ECPublicKeyParameters staticPublicKey; private readonly ECPublicKeyParameters ephemeralPublicKey; - public MqvPublicParameters( + public MqvPublicParameters( ECPublicKeyParameters staticPublicKey, ECPublicKeyParameters ephemeralPublicKey) { - this.staticPublicKey = staticPublicKey; + if (staticPublicKey == null) + throw new ArgumentNullException("staticPublicKey"); + if (ephemeralPublicKey == null) + throw new ArgumentNullException("ephemeralPublicKey"); + if (!staticPublicKey.Parameters.Equals(ephemeralPublicKey.Parameters)) + throw new ArgumentException("Static and ephemeral public keys have different domain parameters"); + + this.staticPublicKey = staticPublicKey; this.ephemeralPublicKey = ephemeralPublicKey; - } + } - public ECPublicKeyParameters StaticPublicKey + public virtual ECPublicKeyParameters StaticPublicKey { get { return staticPublicKey; } } - public ECPublicKeyParameters EphemeralPublicKey + public virtual ECPublicKeyParameters EphemeralPublicKey { get { return ephemeralPublicKey; } } diff --git a/crypto/src/crypto/tls/CertificateType.cs b/crypto/src/crypto/tls/CertificateType.cs new file mode 100644 index 000000000..47ec05c80 --- /dev/null +++ b/crypto/src/crypto/tls/CertificateType.cs @@ -0,0 +1,18 @@ +using System; + +namespace Org.BouncyCastle.Crypto.Tls +{ + /** + * RFC 6091 + */ + public class CertificateType + { + public const byte X509 = 0; + public const byte OpenPGP = 1; + + /* + * RFC 7250 + */ + public const byte RawPublicKey = 2; + } +} 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; } diff --git a/crypto/src/crypto/tls/CipherSuite.cs b/crypto/src/crypto/tls/CipherSuite.cs index 265174341..679a8be85 100644 --- a/crypto/src/crypto/tls/CipherSuite.cs +++ b/crypto/src/crypto/tls/CipherSuite.cs @@ -347,7 +347,7 @@ namespace Org.BouncyCastle.Crypto.Tls public const int DRAFT_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAE; /* - * draft-zauner-tls-aes-ocb-03 (code points TBD) + * draft-zauner-tls-aes-ocb-04 (code points TBD) */ public const int DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB = 0xFF00; public const int DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB = 0xFF01; diff --git a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs index 1e03ec3a8..af0ec126a 100644 --- a/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs +++ b/crypto/src/crypto/tls/DefaultTlsCipherFactory.cs @@ -107,7 +107,7 @@ namespace Org.BouncyCastle.Crypto.Tls protected virtual TlsAeadCipher CreateCipher_Aes_Ocb(TlsContext context, int cipherKeySize, int macSize) { return new TlsAeadCipher(context, CreateAeadBlockCipher_Aes_Ocb(), - CreateAeadBlockCipher_Aes_Ocb(), cipherKeySize, macSize, TlsAeadCipher.NONCE_DRAFT_ZAUNER_TLS_AES_OCB); + CreateAeadBlockCipher_Aes_Ocb(), cipherKeySize, macSize, TlsAeadCipher.NONCE_DRAFT_CHACHA20_POLY1305); } /// <exception cref="IOException"></exception> diff --git a/crypto/src/crypto/tls/DtlsClientProtocol.cs b/crypto/src/crypto/tls/DtlsClientProtocol.cs index abb402077..90430d772 100644 --- a/crypto/src/crypto/tls/DtlsClientProtocol.cs +++ b/crypto/src/crypto/tls/DtlsClientProtocol.cs @@ -53,19 +53,29 @@ namespace Org.BouncyCastle.Crypto.Tls } catch (TlsFatalAlert fatalAlert) { - recordLayer.Fail(fatalAlert.AlertDescription); + AbortClientHandshake(state, recordLayer, fatalAlert.AlertDescription); throw fatalAlert; } catch (IOException e) { - recordLayer.Fail(AlertDescription.internal_error); + AbortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw e; } catch (Exception e) { - recordLayer.Fail(AlertDescription.internal_error); + AbortClientHandshake(state, recordLayer, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } + finally + { + securityParameters.Clear(); + } + } + + internal virtual void AbortClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription) + { + recordLayer.Fail(alertDescription); + InvalidateSession(state); } internal virtual DtlsTransport ClientHandshake(ClientHandshakeState state, DtlsRecordLayer recordLayer) diff --git a/crypto/src/crypto/tls/DtlsRecordLayer.cs b/crypto/src/crypto/tls/DtlsRecordLayer.cs index 6796f4cbb..4a781b5b5 100644 --- a/crypto/src/crypto/tls/DtlsRecordLayer.cs +++ b/crypto/src/crypto/tls/DtlsRecordLayer.cs @@ -237,7 +237,7 @@ namespace Org.BouncyCastle.Crypto.Tls if (alertLevel == AlertLevel.fatal) { - Fail(alertDescription); + Failed(); throw new TlsFatalAlert(alertDescription); } @@ -375,6 +375,16 @@ namespace Org.BouncyCastle.Crypto.Tls } } + internal virtual void Failed() + { + if (!mClosed) + { + mFailed = true; + + CloseTransport(); + } + } + internal virtual void Fail(byte alertDescription) { if (!mClosed) diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs index d05af193c..fbf33045b 100644 --- a/crypto/src/crypto/tls/DtlsServerProtocol.cs +++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs @@ -54,19 +54,29 @@ namespace Org.BouncyCastle.Crypto.Tls } catch (TlsFatalAlert fatalAlert) { - recordLayer.Fail(fatalAlert.AlertDescription); + AbortServerHandshake(state, recordLayer, fatalAlert.AlertDescription); throw fatalAlert; } catch (IOException e) { - recordLayer.Fail(AlertDescription.internal_error); + AbortServerHandshake(state, recordLayer, AlertDescription.internal_error); throw e; } catch (Exception e) { - recordLayer.Fail(AlertDescription.internal_error); + AbortServerHandshake(state, recordLayer, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } + finally + { + securityParameters.Clear(); + } + } + + internal virtual void AbortServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer, byte alertDescription) + { + recordLayer.Fail(alertDescription); + InvalidateSession(state); } internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer) @@ -263,6 +273,21 @@ namespace Org.BouncyCastle.Crypto.Tls return new DtlsTransport(recordLayer); } + protected virtual void InvalidateSession(ServerHandshakeState state) + { + if (state.sessionParameters != null) + { + state.sessionParameters.Clear(); + state.sessionParameters = null; + } + + if (state.tlsSession != null) + { + state.tlsSession.Invalidate(); + state.tlsSession = null; + } + } + protected virtual byte[] GenerateCertificateRequest(ServerHandshakeState state, CertificateRequest certificateRequest) { MemoryStream buf = new MemoryStream(); @@ -650,6 +675,9 @@ namespace Org.BouncyCastle.Crypto.Tls { internal TlsServer server = null; internal TlsServerContextImpl serverContext = null; + internal TlsSession tlsSession = null; + internal SessionParameters sessionParameters = null; + internal SessionParameters.Builder sessionParametersBuilder = null; internal int[] offeredCipherSuites = null; internal byte[] offeredCompressionMethods = null; internal IDictionary clientExtensions = null; diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs index 04c1733cb..96037ed20 100644 --- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs +++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs @@ -62,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Tls [Obsolete] public const int AEAD_CHACHA20_POLY1305 = CHACHA20_POLY1305; /* - * draft-zauner-tls-aes-ocb-03 + * draft-zauner-tls-aes-ocb-04 */ public const int AES_128_OCB_TAGLEN96 = 103; public const int AES_256_OCB_TAGLEN96 = 104; diff --git a/crypto/src/crypto/tls/NameType.cs b/crypto/src/crypto/tls/NameType.cs index 25f6046fc..782164215 100644 --- a/crypto/src/crypto/tls/NameType.cs +++ b/crypto/src/crypto/tls/NameType.cs @@ -8,5 +8,10 @@ namespace Org.BouncyCastle.Crypto.Tls * RFC 3546 3.1. */ public const byte host_name = 0; + + public static bool IsValid(byte nameType) + { + return nameType == host_name; + } } } diff --git a/crypto/src/crypto/tls/ServerNameList.cs b/crypto/src/crypto/tls/ServerNameList.cs index 13da79bf6..5b5b90e58 100644 --- a/crypto/src/crypto/tls/ServerNameList.cs +++ b/crypto/src/crypto/tls/ServerNameList.cs @@ -15,8 +15,8 @@ namespace Org.BouncyCastle.Crypto.Tls */ public ServerNameList(IList serverNameList) { - if (serverNameList == null || serverNameList.Count < 1) - throw new ArgumentException("must not be null or empty", "serverNameList"); + if (serverNameList == null) + throw new ArgumentNullException("serverNameList"); this.mServerNameList = serverNameList; } @@ -40,8 +40,13 @@ namespace Org.BouncyCastle.Crypto.Tls { MemoryStream buf = new MemoryStream(); + byte[] nameTypesSeen = TlsUtilities.EmptyBytes; foreach (ServerName entry in ServerNames) { + nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType); + if (nameTypesSeen == null) + throw new TlsFatalAlert(AlertDescription.internal_error); + entry.Encode(buf); } @@ -68,14 +73,32 @@ namespace Org.BouncyCastle.Crypto.Tls MemoryStream buf = new MemoryStream(data, false); + byte[] nameTypesSeen = TlsUtilities.EmptyBytes; IList server_name_list = Platform.CreateArrayList(); while (buf.Position < buf.Length) { ServerName entry = ServerName.Parse(buf); + + nameTypesSeen = CheckNameType(nameTypesSeen, entry.NameType); + if (nameTypesSeen == null) + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + server_name_list.Add(entry); } return new ServerNameList(server_name_list); } + + private static byte[] CheckNameType(byte[] nameTypesSeen, byte nameType) + { + /* + * RFC 6066 3. The ServerNameList MUST NOT contain more than one name of the same + * name_type. + */ + if (!NameType.IsValid(nameType) || Arrays.Contains(nameTypesSeen, nameType)) + return null; + + return Arrays.Append(nameTypesSeen, nameType); + } } } diff --git a/crypto/src/crypto/tls/TlsAeadCipher.cs b/crypto/src/crypto/tls/TlsAeadCipher.cs index bff719db1..cc0575cf0 100644 --- a/crypto/src/crypto/tls/TlsAeadCipher.cs +++ b/crypto/src/crypto/tls/TlsAeadCipher.cs @@ -10,8 +10,14 @@ namespace Org.BouncyCastle.Crypto.Tls public class TlsAeadCipher : TlsCipher { + // TODO[draft-zauner-tls-aes-ocb-04] Apply data volume limit described in section 8.4 + public const int NONCE_RFC5288 = 1; - internal const int NONCE_DRAFT_ZAUNER_TLS_AES_OCB = 2; + + /* + * draft-zauner-tls-aes-ocb-04 specifies the nonce construction from draft-ietf-tls-chacha20-poly1305-04 + */ + internal const int NONCE_DRAFT_CHACHA20_POLY1305 = 2; protected readonly TlsContext context; protected readonly int macSize; @@ -23,6 +29,8 @@ namespace Org.BouncyCastle.Crypto.Tls protected readonly byte[] encryptImplicitNonce, decryptImplicitNonce; + protected readonly int nonceMode; + /// <exception cref="IOException"></exception> public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher, int cipherKeySize, int macSize) @@ -37,12 +45,19 @@ namespace Org.BouncyCastle.Crypto.Tls if (!TlsUtilities.IsTlsV12(context)) throw new TlsFatalAlert(AlertDescription.internal_error); + this.nonceMode = nonceMode; + + // TODO SecurityParameters.fixed_iv_length + int fixed_iv_length; + switch (nonceMode) { case NONCE_RFC5288: + fixed_iv_length = 4; this.record_iv_length = 8; break; - case NONCE_DRAFT_ZAUNER_TLS_AES_OCB: + case NONCE_DRAFT_CHACHA20_POLY1305: + fixed_iv_length = 12; this.record_iv_length = 0; break; default: @@ -52,9 +67,6 @@ namespace Org.BouncyCastle.Crypto.Tls this.context = context; this.macSize = macSize; - // TODO SecurityParameters.fixed_iv_length - int fixed_iv_length = 4; - int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length); byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size); @@ -93,7 +105,7 @@ namespace Org.BouncyCastle.Crypto.Tls decryptKey = server_write_key; } - byte[] dummyNonce = new byte[fixed_iv_length + 8]; + byte[] dummyNonce = new byte[fixed_iv_length + record_iv_length]; this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce)); this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce)); @@ -108,16 +120,25 @@ namespace Org.BouncyCastle.Crypto.Tls /// <exception cref="IOException"></exception> public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len) { - byte[] nonce = new byte[this.encryptImplicitNonce.Length + 8]; - Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length); + byte[] nonce = new byte[encryptImplicitNonce.Length + record_iv_length]; - /* - * RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number. - * draft-zauner-tls-aes-ocb-03: uses the sequence number (not included in message). - * - * (May need review for other AEAD ciphers). - */ - TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length); + switch (nonceMode) + { + case NONCE_RFC5288: + Array.Copy(encryptImplicitNonce, 0, nonce, 0, encryptImplicitNonce.Length); + // RFC 5288/6655: The nonce_explicit MAY be the 64-bit sequence number. + TlsUtilities.WriteUint64(seqNo, nonce, encryptImplicitNonce.Length); + break; + case NONCE_DRAFT_CHACHA20_POLY1305: + TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8); + for (int i = 0; i < encryptImplicitNonce.Length; ++i) + { + nonce[i] ^= encryptImplicitNonce[i]; + } + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } int plaintextOffset = offset; int plaintextLength = len; @@ -159,16 +180,23 @@ namespace Org.BouncyCastle.Crypto.Tls if (GetPlaintextLimit(len) < 0) throw new TlsFatalAlert(AlertDescription.decode_error); - byte[] nonce = new byte[this.decryptImplicitNonce.Length + 8]; - Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length); - //Array.Copy(ciphertext, offset, nonce, decryptImplicitNonce.Length, nonce_explicit_length); - if (record_iv_length == 0) - { - TlsUtilities.WriteUint64(seqNo, nonce, decryptImplicitNonce.Length); - } - else + byte[] nonce = new byte[decryptImplicitNonce.Length + record_iv_length]; + + switch (nonceMode) { - Array.Copy(ciphertext, offset, nonce, nonce.Length - record_iv_length, record_iv_length); + case NONCE_RFC5288: + Array.Copy(decryptImplicitNonce, 0, nonce, 0, decryptImplicitNonce.Length); + Array.Copy(ciphertext, offset, nonce, nonce.Length - record_iv_length, record_iv_length); + break; + case NONCE_DRAFT_CHACHA20_POLY1305: + TlsUtilities.WriteUint64(seqNo, nonce, nonce.Length - 8); + for (int i = 0; i < decryptImplicitNonce.Length; ++i) + { + nonce[i] ^= decryptImplicitNonce[i]; + } + break; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); } int ciphertextOffset = offset + record_iv_length; diff --git a/crypto/src/crypto/tls/TlsDHUtilities.cs b/crypto/src/crypto/tls/TlsDHUtilities.cs index f94163c6a..7a44670fd 100644 --- a/crypto/src/crypto/tls/TlsDHUtilities.cs +++ b/crypto/src/crypto/tls/TlsDHUtilities.cs @@ -375,7 +375,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: /* - * draft-zauner-tls-aes-ocb-03 + * draft-zauner-tls-aes-ocb-04 */ case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_128_OCB: case CipherSuite.DRAFT_TLS_DHE_RSA_WITH_AES_256_OCB: @@ -391,7 +391,8 @@ namespace Org.BouncyCastle.Crypto.Tls public static bool AreCompatibleParameters(DHParameters a, DHParameters b) { - return a.P.Equals(b.P) && a.G.Equals(b.G); + return a.P.Equals(b.P) && a.G.Equals(b.G) + && (a.Q == null || b.Q == null || a.Q.Equals(b.Q)); } public static byte[] CalculateDHBasicAgreement(DHPublicKeyParameters publicKey, diff --git a/crypto/src/crypto/tls/TlsEccUtilities.cs b/crypto/src/crypto/tls/TlsEccUtilities.cs index 5a4c2b60e..a5c8fa910 100644 --- a/crypto/src/crypto/tls/TlsEccUtilities.cs +++ b/crypto/src/crypto/tls/TlsEccUtilities.cs @@ -261,7 +261,7 @@ namespace Org.BouncyCastle.Crypto.Tls case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: /* - * draft-zauner-tls-aes-ocb-03 + * draft-zauner-tls-aes-ocb-04 */ case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_128_OCB: case CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_AES_256_OCB: @@ -279,8 +279,7 @@ namespace Org.BouncyCastle.Crypto.Tls public static bool AreOnSameCurve(ECDomainParameters a, ECDomainParameters b) { - // TODO Move to ECDomainParameters.Equals() or other utility method? - return a.Curve.Equals(b.Curve) && a.G.Equals(b.G) && a.N.Equals(b.N) && a.H.Equals(b.H); + return a != null && a.Equals(b); } public static bool IsSupportedNamedCurve(int namedCurve) diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs index df1c50f02..6d5c93f40 100644 --- a/crypto/src/crypto/tls/TlsProtocol.cs +++ b/crypto/src/crypto/tls/TlsProtocol.cs @@ -34,6 +34,13 @@ namespace Org.BouncyCastle.Crypto.Tls protected const short CS_END = 16; /* + * Different modes to handle the known IV weakness + */ + protected const short ADS_MODE_1_Nsub1 = 0; // 1/n-1 record splitting + protected const short ADS_MODE_0_N = 1; // 0/n record splitting + protected const short ADS_MODE_0_N_FIRSTONLY = 2; // 0/n record splitting on first data fragment only + + /* * Queues for data from some protocols. */ private ByteQueue mApplicationDataQueue = new ByteQueue(); @@ -52,7 +59,8 @@ namespace Org.BouncyCastle.Crypto.Tls private volatile bool mClosed = false; private volatile bool mFailedWithError = false; private volatile bool mAppDataReady = false; - private volatile bool mSplitApplicationDataRecords = true; + private volatile bool mAppDataSplitEnabled = true; + private volatile int mAppDataSplitMode = ADS_MODE_1_Nsub1; private byte[] mExpectedVerifyData = null; protected TlsSession mTlsSession = null; @@ -175,7 +183,7 @@ namespace Org.BouncyCastle.Crypto.Tls { this.mRecordStream.FinaliseHandshake(); - this.mSplitApplicationDataRecords = !TlsUtilities.IsTlsV11(Context); + this.mAppDataSplitEnabled = !TlsUtilities.IsTlsV11(Context); /* * If this was an initial handshake, we are now ready to send and receive application data. @@ -556,16 +564,29 @@ namespace Org.BouncyCastle.Crypto.Tls * NOTE: Actually, implementations appear to have settled on 1/n-1 record splitting. */ - if (this.mSplitApplicationDataRecords) + if (this.mAppDataSplitEnabled) { /* * Protect against known IV attack! * * DO NOT REMOVE THIS CODE, EXCEPT YOU KNOW EXACTLY WHAT YOU ARE DOING HERE. */ - SafeWriteRecord(ContentType.application_data, buf, offset, 1); - ++offset; - --len; + switch (mAppDataSplitMode) + { + case ADS_MODE_0_N: + SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0); + break; + case ADS_MODE_0_N_FIRSTONLY: + this.mAppDataSplitEnabled = false; + SafeWriteRecord(ContentType.application_data, TlsUtilities.EmptyBytes, 0, 0); + break; + case ADS_MODE_1_Nsub1: + default: + SafeWriteRecord(ContentType.application_data, buf, offset, 1); + ++offset; + --len; + break; + } } if (len > 0) @@ -579,6 +600,14 @@ namespace Org.BouncyCastle.Crypto.Tls } } + protected virtual void SetAppDataSplitMode(int appDataSplitMode) + { + if (appDataSplitMode < ADS_MODE_1_Nsub1 || appDataSplitMode > ADS_MODE_0_N_FIRSTONLY) + throw new ArgumentException("Illegal appDataSplitMode mode: " + appDataSplitMode, "appDataSplitMode"); + + this.mAppDataSplitMode = appDataSplitMode; + } + protected virtual void WriteHandshakeMessage(byte[] buf, int off, int len) { while (len > 0) @@ -1086,20 +1115,32 @@ namespace Org.BouncyCastle.Crypto.Tls { MemoryStream buf = new MemoryStream(); - foreach (int extension_type in extensions.Keys) - { - byte[] extension_data = (byte[])extensions[extension_type]; - - TlsUtilities.CheckUint16(extension_type); - TlsUtilities.WriteUint16(extension_type, buf); - TlsUtilities.WriteOpaque16(extension_data, buf); - } + /* + * NOTE: There are reports of servers that don't accept a zero-length extension as the last + * one, so we write out any zero-length ones first as a best-effort workaround. + */ + WriteSelectedExtensions(buf, extensions, true); + WriteSelectedExtensions(buf, extensions, false); byte[] extBytes = buf.ToArray(); TlsUtilities.WriteOpaque16(extBytes, output); } + protected internal static void WriteSelectedExtensions(Stream output, IDictionary extensions, bool selectEmpty) + { + foreach (int extension_type in extensions.Keys) + { + byte[] extension_data = (byte[])extensions[extension_type]; + if (selectEmpty == (extension_data.Length == 0)) + { + TlsUtilities.CheckUint16(extension_type); + TlsUtilities.WriteUint16(extension_type, output); + TlsUtilities.WriteOpaque16(extension_data, output); + } + } + } + protected internal static void WriteSupplementalData(Stream output, IList supplementalData) { MemoryStream buf = new MemoryStream(); diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs index 25908d163..d51a8ff48 100644 --- a/crypto/src/crypto/tls/TlsUtilities.cs +++ b/crypto/src/crypto/tls/TlsUtilities.cs @@ -1246,6 +1246,7 @@ namespace Org.BouncyCastle.Crypto.Tls case EncryptionAlgorithm.SEED_CBC: return CipherType.block; + case EncryptionAlgorithm.NULL: case EncryptionAlgorithm.RC4_40: case EncryptionAlgorithm.RC4_128: return CipherType.stream; diff --git a/crypto/src/math/ec/multiplier/WNafUtilities.cs b/crypto/src/math/ec/multiplier/WNafUtilities.cs index 5491297d7..7d565dfbd 100644 --- a/crypto/src/math/ec/multiplier/WNafUtilities.cs +++ b/crypto/src/math/ec/multiplier/WNafUtilities.cs @@ -423,7 +423,7 @@ namespace Org.BouncyCastle.Math.EC.Multiplier * 1) additions do not use the curve's A, B coefficients. * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... */ - if (ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64) + if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64) { switch (c.CoordinateSystem) { diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs index 819c52062..1d3b64d32 100644 --- a/crypto/src/math/raw/Nat128.cs +++ b/crypto/src/math/raw/Nat128.cs @@ -626,8 +626,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -702,8 +702,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs index 153ac0a43..1fd00e576 100644 --- a/crypto/src/math/raw/Nat160.cs +++ b/crypto/src/math/raw/Nat160.cs @@ -604,8 +604,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -619,8 +619,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -699,8 +699,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -714,8 +714,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; diff --git a/crypto/src/math/raw/Nat192.cs b/crypto/src/math/raw/Nat192.cs index 4797609ee..3099bafab 100644 --- a/crypto/src/math/raw/Nat192.cs +++ b/crypto/src/math/raw/Nat192.cs @@ -706,8 +706,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -721,8 +721,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -738,8 +738,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[5]; - ulong zz_9 = zz[9]; - ulong zz_10 = zz[10]; + ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -822,8 +822,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -837,8 +837,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -854,8 +854,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[xOff + 5]; - ulong zz_9 = zz[zzOff + 9]; - ulong zz_10 = zz[zzOff + 10]; + ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; diff --git a/crypto/src/math/raw/Nat224.cs b/crypto/src/math/raw/Nat224.cs index 940e930ac..978caf265 100644 --- a/crypto/src/math/raw/Nat224.cs +++ b/crypto/src/math/raw/Nat224.cs @@ -786,8 +786,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -801,8 +801,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -818,8 +818,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[5]; - ulong zz_9 = zz[9]; - ulong zz_10 = zz[10]; + ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -837,8 +837,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[6]; - ulong zz_11 = zz[11]; - ulong zz_12 = zz[12]; + ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; @@ -925,8 +925,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -940,8 +940,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -957,8 +957,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[xOff + 5]; - ulong zz_9 = zz[zzOff + 9]; - ulong zz_10 = zz[zzOff + 10]; + ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -976,8 +976,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[xOff + 6]; - ulong zz_11 = zz[zzOff + 11]; - ulong zz_12 = zz[zzOff + 12]; + ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; diff --git a/crypto/src/math/raw/Nat256.cs b/crypto/src/math/raw/Nat256.cs index 19455031a..09c751a5a 100644 --- a/crypto/src/math/raw/Nat256.cs +++ b/crypto/src/math/raw/Nat256.cs @@ -917,8 +917,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[3]; - ulong zz_5 = zz[5]; - ulong zz_6 = zz[6]; + ulong zz_5 = zz[5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -932,8 +932,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[4]; - ulong zz_7 = zz[7]; - ulong zz_8 = zz[8]; + ulong zz_7 = zz[7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -949,8 +949,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[5]; - ulong zz_9 = zz[9]; - ulong zz_10 = zz[10]; + ulong zz_9 = zz[9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -968,8 +968,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[6]; - ulong zz_11 = zz[11]; - ulong zz_12 = zz[12]; + ulong zz_11 = zz[11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; @@ -989,8 +989,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_7 = x[7]; - ulong zz_13 = zz[13]; - ulong zz_14 = zz[14]; + ulong zz_13 = zz[13] + (zz_12 >> 32); zz_12 &= M; + ulong zz_14 = zz[14] + (zz_13 >> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (uint)zz_7; @@ -1081,8 +1081,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_3 = x[xOff + 3]; - ulong zz_5 = zz[zzOff + 5]; - ulong zz_6 = zz[zzOff + 6]; + ulong zz_5 = zz[zzOff + 5] + (zz_4 >> 32); zz_4 &= M; + ulong zz_6 = zz[zzOff + 6] + (zz_5 >> 32); zz_5 &= M; { zz_3 += x_3 * x_0; w = (uint)zz_3; @@ -1096,8 +1096,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_4 = x[xOff + 4]; - ulong zz_7 = zz[zzOff + 7]; - ulong zz_8 = zz[zzOff + 8]; + ulong zz_7 = zz[zzOff + 7] + (zz_6 >> 32); zz_6 &= M; + ulong zz_8 = zz[zzOff + 8] + (zz_7 >> 32); zz_7 &= M; { zz_4 += x_4 * x_0; w = (uint)zz_4; @@ -1113,8 +1113,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_5 = x[xOff + 5]; - ulong zz_9 = zz[zzOff + 9]; - ulong zz_10 = zz[zzOff + 10]; + ulong zz_9 = zz[zzOff + 9] + (zz_8 >> 32); zz_8 &= M; + ulong zz_10 = zz[zzOff + 10] + (zz_9 >> 32); zz_9 &= M; { zz_5 += x_5 * x_0; w = (uint)zz_5; @@ -1132,8 +1132,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_6 = x[xOff + 6]; - ulong zz_11 = zz[zzOff + 11]; - ulong zz_12 = zz[zzOff + 12]; + ulong zz_11 = zz[zzOff + 11] + (zz_10 >> 32); zz_10 &= M; + ulong zz_12 = zz[zzOff + 12] + (zz_11 >> 32); zz_11 &= M; { zz_6 += x_6 * x_0; w = (uint)zz_6; @@ -1153,8 +1153,8 @@ namespace Org.BouncyCastle.Math.Raw } ulong x_7 = x[xOff + 7]; - ulong zz_13 = zz[zzOff + 13]; - ulong zz_14 = zz[zzOff + 14]; + ulong zz_13 = zz[zzOff + 13] + (zz_12 >> 32); zz_12 &= M; + ulong zz_14 = zz[zzOff + 14] + (zz_13 >> 32); zz_13 &= M; { zz_7 += x_7 * x_0; w = (uint)zz_7; diff --git a/crypto/src/openpgp/PgpSignature.cs b/crypto/src/openpgp/PgpSignature.cs index 3bb6f2f0e..c8c541bef 100644 --- a/crypto/src/openpgp/PgpSignature.cs +++ b/crypto/src/openpgp/PgpSignature.cs @@ -84,6 +84,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp get { return sigPck.HashAlgorithm; } } + /// <summary>Return true if this signature represents a certification.</summary> + public bool IsCertification() + { + return IsCertification(SignatureType); + } + public void InitVerify( PgpPublicKey pubKey) { @@ -418,5 +424,24 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp throw new PgpException("exception preparing key.", e); } } + + /// <summary> + /// Return true if the passed in signature type represents a certification, false if the signature type is not. + /// </summary> + /// <param name="signatureType"></param> + /// <returns>true if signatureType is a certification, false otherwise.</returns> + public static bool IsCertification(int signatureType) + { + switch (signatureType) + { + case DefaultCertification: + case NoCertification: + case CasualCertification: + case PositiveCertification: + return true; + default: + return false; + } + } } } diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs index cb831acc2..bd639a336 100644 --- a/crypto/src/security/SecureRandom.cs +++ b/crypto/src/security/SecureRandom.cs @@ -170,6 +170,7 @@ namespace Org.BouncyCastle.Security public override int Next(int maxValue) { + if (maxValue < 2) { if (maxValue < 0) @@ -178,13 +179,16 @@ namespace Org.BouncyCastle.Security return 0; } + int bits; + // Test whether maxValue is a power of 2 if ((maxValue & (maxValue - 1)) == 0) { - return NextInt() & (maxValue - 1); + bits = NextInt() & int.MaxValue; + return (int)(((long)bits * maxValue) >> 31); } - int bits, result; + int result; do { bits = NextInt() & int.MaxValue; diff --git a/crypto/src/tsp/TimeStampRequest.cs b/crypto/src/tsp/TimeStampRequest.cs index f54d33e04..0b41adef7 100644 --- a/crypto/src/tsp/TimeStampRequest.cs +++ b/crypto/src/tsp/TimeStampRequest.cs @@ -130,34 +130,24 @@ namespace Org.BouncyCastle.Tsp IList extensions) { if (!algorithms.Contains(this.MessageImprintAlgOid)) - { - throw new TspValidationException("request contains unknown algorithm.", PkiFailureInfo.BadAlg); - } + throw new TspValidationException("request contains unknown algorithm", PkiFailureInfo.BadAlg); - if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy)) - { - throw new TspValidationException("request contains unknown policy.", PkiFailureInfo.UnacceptedPolicy); - } + if (policies != null && this.ReqPolicy != null && !policies.Contains(this.ReqPolicy)) + throw new TspValidationException("request contains unknown policy", PkiFailureInfo.UnacceptedPolicy); - if (this.Extensions != null && extensions != null) + if (this.Extensions != null && extensions != null) { foreach (DerObjectIdentifier oid in this.Extensions.ExtensionOids) { if (!extensions.Contains(oid.Id)) - { - throw new TspValidationException("request contains unknown extension.", - PkiFailureInfo.UnacceptedExtension); - } + throw new TspValidationException("request contains unknown extension", PkiFailureInfo.UnacceptedExtension); } } int digestLength = TspUtil.GetDigestLength(this.MessageImprintAlgOid); if (digestLength != this.GetMessageImprintDigest().Length) - { - throw new TspValidationException("imprint digest the wrong length.", - PkiFailureInfo.BadDataFormat); - } + throw new TspValidationException("imprint digest the wrong length", PkiFailureInfo.BadDataFormat); } /** diff --git a/crypto/src/util/zlib/ZInputStream.cs b/crypto/src/util/zlib/ZInputStream.cs index 4b7351555..434fe95c8 100644 --- a/crypto/src/util/zlib/ZInputStream.cs +++ b/crypto/src/util/zlib/ZInputStream.cs @@ -42,9 +42,16 @@ namespace Org.BouncyCastle.Utilities.Zlib public class ZInputStream : Stream { - private const int BufferSize = 512; + private static ZStream GetDefaultZStream(bool nowrap) + { + ZStream z = new ZStream(); + z.inflateInit(nowrap); + return z; + } + + private const int BufferSize = 512; - protected ZStream z = new ZStream(); + protected ZStream z; protected int flushLevel = JZlib.Z_NO_FLUSH; // TODO Allow custom buf protected byte[] buf = new byte[BufferSize]; @@ -62,24 +69,46 @@ namespace Org.BouncyCastle.Utilities.Zlib } public ZInputStream(Stream input, bool nowrap) + : this(input, GetDefaultZStream(nowrap)) + { + } + + public ZInputStream(Stream input, ZStream z) + : base() { Debug.Assert(input.CanRead); - this.input = input; - this.z.inflateInit(nowrap); - this.compress = false; - this.z.next_in = buf; + if (z == null) + { + z = new ZStream(); + } + + if (z.istate == null && z.dstate == null) + { + z.inflateInit(); + } + + this.input = input; + this.compress = (z.istate == null); + this.z = z; + this.z.next_in = buf; this.z.next_in_index = 0; this.z.avail_in = 0; } - public ZInputStream(Stream input, int level) + public ZInputStream(Stream input, int level) + : this(input, level, false) + { + } + + public ZInputStream(Stream input, int level, bool nowrap) { Debug.Assert(input.CanRead); this.input = input; - this.z.deflateInit(level); - this.compress = true; + this.compress = true; + this.z = new ZStream(); + this.z.deflateInit(level, nowrap); this.z.next_in = buf; this.z.next_in_index = 0; this.z.avail_in = 0; diff --git a/crypto/src/util/zlib/ZOutputStream.cs b/crypto/src/util/zlib/ZOutputStream.cs index d9f005f69..1633b2d8f 100644 --- a/crypto/src/util/zlib/ZOutputStream.cs +++ b/crypto/src/util/zlib/ZOutputStream.cs @@ -42,7 +42,14 @@ namespace Org.BouncyCastle.Utilities.Zlib public class ZOutputStream : Stream { - private const int BufferSize = 512; + private static ZStream GetDefaultZStream(bool nowrap) + { + ZStream z = new ZStream(); + z.inflateInit(nowrap); + return z; + } + + private const int BufferSize = 512; protected ZStream z; protected int flushLevel = JZlib.Z_NO_FLUSH; @@ -55,9 +62,14 @@ namespace Org.BouncyCastle.Utilities.Zlib protected bool closed; public ZOutputStream(Stream output) - : this(output, null) - { - } + : this(output, false) + { + } + + public ZOutputStream(Stream output, bool nowrap) + : this(output, GetDefaultZStream(nowrap)) + { + } public ZOutputStream(Stream output, ZStream z) : base() @@ -67,12 +79,16 @@ namespace Org.BouncyCastle.Utilities.Zlib if (z == null) { z = new ZStream(); + } + + if (z.istate == null && z.dstate == null) + { z.inflateInit(); } this.output = output; + this.compress = (z.istate == null); this.z = z; - this.compress = false; } public ZOutputStream(Stream output, int level) @@ -86,9 +102,9 @@ namespace Org.BouncyCastle.Utilities.Zlib Debug.Assert(output.CanWrite); this.output = output; + this.compress = true; this.z = new ZStream(); this.z.deflateInit(level, nowrap); - this.compress = true; } public sealed override bool CanRead { get { return false; } } |