diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
index 0ffd65dfc..7266e4b4c 100644
--- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -110,5 +110,26 @@ namespace Org.BouncyCastle.Asn1.BC
public static readonly DerObjectIdentifier bc_ext = bc.Branch("4");
public static readonly DerObjectIdentifier linkedCertificate = bc_ext.Branch("1");
+
+ /**
+ * KEM(4) algorithms
+ */
+ public static readonly DerObjectIdentifier bc_kem = bc.Branch("5");
+
+ /**
+ * Classic McEliece
+ */
+ public static readonly DerObjectIdentifier pqc_kem_mceliece = bc_kem.Branch("1");
+
+ public static readonly DerObjectIdentifier mceliece348864_r3 = pqc_kem_mceliece.Branch("1");
+ public static readonly DerObjectIdentifier mceliece348864f_r3 = pqc_kem_mceliece.Branch("2");
+ public static readonly DerObjectIdentifier mceliece460896_r3 = pqc_kem_mceliece.Branch("3");
+ public static readonly DerObjectIdentifier mceliece460896f_r3 = pqc_kem_mceliece.Branch("4");
+ public static readonly DerObjectIdentifier mceliece6688128_r3 = pqc_kem_mceliece.Branch("5");
+ public static readonly DerObjectIdentifier mceliece6688128f_r3 = pqc_kem_mceliece.Branch("6");
+ public static readonly DerObjectIdentifier mceliece6960119_r3 = pqc_kem_mceliece.Branch("7");
+ public static readonly DerObjectIdentifier mceliece6960119f_r3 = pqc_kem_mceliece.Branch("8");
+ public static readonly DerObjectIdentifier mceliece8192128_r3 = pqc_kem_mceliece.Branch("9");
+ public static readonly DerObjectIdentifier mceliece8192128f_r3 = pqc_kem_mceliece.Branch("10");
}
}
diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs
index 45dc96885..86ad11207 100644
--- a/crypto/src/bcpg/SignatureSubpacketsReader.cs
+++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -90,33 +90,37 @@ namespace Org.BouncyCastle.Bcpg
switch (type)
{
- case SignatureSubpacketTag.CreationTime:
- return new SignatureCreationTime(isCritical, isLongLength, data);
- case SignatureSubpacketTag.KeyExpireTime:
- return new KeyExpirationTime(isCritical, isLongLength, data);
- case SignatureSubpacketTag.ExpireTime:
- return new SignatureExpirationTime(isCritical, isLongLength, data);
- case SignatureSubpacketTag.Revocable:
- return new Revocable(isCritical, isLongLength, data);
- case SignatureSubpacketTag.Exportable:
- return new Exportable(isCritical, isLongLength, data);
- case SignatureSubpacketTag.IssuerKeyId:
- return new IssuerKeyId(isCritical, isLongLength, data);
- case SignatureSubpacketTag.TrustSig:
- return new TrustSignature(isCritical, isLongLength, data);
- case SignatureSubpacketTag.PreferredCompressionAlgorithms:
- case SignatureSubpacketTag.PreferredHashAlgorithms:
- case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
- return new PreferredAlgorithms(type, isCritical, isLongLength, data);
- case SignatureSubpacketTag.KeyFlags:
- return new KeyFlags(isCritical, isLongLength, data);
- case SignatureSubpacketTag.PrimaryUserId:
- return new PrimaryUserId(isCritical, isLongLength, data);
- case SignatureSubpacketTag.SignerUserId:
- return new SignerUserId(isCritical, isLongLength, data);
- case SignatureSubpacketTag.NotationData:
- return new NotationData(isCritical, isLongLength, data);
- }
+ case SignatureSubpacketTag.CreationTime:
+ return new SignatureCreationTime(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.KeyExpireTime:
+ return new KeyExpirationTime(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.ExpireTime:
+ return new SignatureExpirationTime(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.Revocable:
+ return new Revocable(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.Exportable:
+ return new Exportable(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.IssuerKeyId:
+ return new IssuerKeyId(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.TrustSig:
+ return new TrustSignature(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.PreferredCompressionAlgorithms:
+ case SignatureSubpacketTag.PreferredHashAlgorithms:
+ case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
+ return new PreferredAlgorithms(type, isCritical, isLongLength, data);
+ case SignatureSubpacketTag.KeyFlags:
+ return new KeyFlags(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.PrimaryUserId:
+ return new PrimaryUserId(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.SignerUserId:
+ return new SignerUserId(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.NotationData:
+ return new NotationData(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.RevocationReason:
+ return new RevocationReason(isCritical, isLongLength, data);
+ case SignatureSubpacketTag.RevocationKey:
+ return new RevocationKey(isCritical, isLongLength, data);
+ }
return new SignatureSubpacket(type, isCritical, isLongLength, data);
}
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index 295a43aac..f3550b9cd 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -213,7 +213,8 @@ namespace Org.BouncyCastle.Crypto.Encodings
// on encryption, we need to make sure our decrypted block comes back
// the same size.
//
- bool wrongData = (block.Length < (2 * defHash.Length) + 1);
+ // i.e. wrong when block.length < (2 * defHash.length) + 1
+ int wrongMask = (block.Length - ((2 * defHash.Length) + 1)) >> 31;
if (data.Length <= block.Length)
{
@@ -222,7 +223,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
else
{
Array.Copy(data, 0, block, 0, block.Length);
- wrongData = true;
+ wrongMask |= 1;
}
//
@@ -250,39 +251,38 @@ namespace Org.BouncyCastle.Crypto.Encodings
// check the hash of the encoding params.
// long check to try to avoid this been a source of a timing attack.
//
- bool defHashWrong = false;
-
for (int i = 0; i != defHash.Length; i++)
{
- if (defHash[i] != block[defHash.Length + i])
- {
- defHashWrong = true;
- }
+ wrongMask |= defHash[i] ^ block[defHash.Length + i];
}
//
// find the data block
//
- int start = block.Length;
+ int start = -1;
for (int index = 2 * defHash.Length; index != block.Length; index++)
{
- if (block[index] != 0 & start == block.Length)
- {
- start = index;
- }
- }
+ int octet = block[index];
- bool dataStartWrong = (start > (block.Length - 1) | block[start] != 1);
+ // i.e. mask will be 0xFFFFFFFF if octet is non-zero and start is (still) negative, else 0.
+ int shouldSetMask = (-octet & start) >> 31;
- start++;
+ start += index & shouldSetMask;
+ }
- if (defHashWrong | wrongData | dataStartWrong)
+ wrongMask |= start >> 31;
+ ++start;
+ wrongMask |= block[start] ^ 1;
+
+ if (wrongMask != 0)
{
Arrays.Fill(block, 0);
throw new InvalidCipherTextException("data wrong");
}
+ ++start;
+
//
// extract the data block
//
diff --git a/crypto/src/crypto/engines/CamelliaEngine.cs b/crypto/src/crypto/engines/CamelliaEngine.cs
index 71bd1b0dc..2222e4b7c 100644
--- a/crypto/src/crypto/engines/CamelliaEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaEngine.cs
@@ -18,7 +18,6 @@ namespace Org.BouncyCastle.Crypto.Engines
private uint[] subkey = new uint[24 * 4];
private uint[] kw = new uint[4 * 2]; // for whitening
private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1)
- private uint[] state = new uint[4]; // for encryption and decryption
private static readonly uint[] SIGMA = new uint[]{
0xa09e667f, 0x3bcc908b,
@@ -540,10 +539,11 @@ namespace Org.BouncyCastle.Crypto.Engines
private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
{
+ uint[] state = new uint[4];
+
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4));
- state[i] ^= kw[i];
+ state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -573,10 +573,11 @@ namespace Org.BouncyCastle.Crypto.Engines
private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
{
+ uint[] state = new uint[4];
+
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4));
- state[i] ^= kw[i];
+ state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -604,6 +605,7 @@ namespace Org.BouncyCastle.Crypto.Engines
uint2bytes(state[3], output, outOff + 4);
uint2bytes(state[0], output, outOff + 8);
uint2bytes(state[1], output, outOff + 12);
+
return BLOCK_SIZE;
}
diff --git a/crypto/src/crypto/engines/CamelliaLightEngine.cs b/crypto/src/crypto/engines/CamelliaLightEngine.cs
index a132227c5..daf0316e2 100644
--- a/crypto/src/crypto/engines/CamelliaLightEngine.cs
+++ b/crypto/src/crypto/engines/CamelliaLightEngine.cs
@@ -18,7 +18,6 @@ namespace Org.BouncyCastle.Crypto.Engines
private uint[] subkey = new uint[24 * 4];
private uint[] kw = new uint[4 * 2]; // for whitening
private uint[] ke = new uint[6 * 2]; // for FL and FL^(-1)
- private uint[] state = new uint[4]; // for encryption and decryption
private static readonly uint[] SIGMA = {
0xa09e667f, 0x3bcc908b,
@@ -452,10 +451,11 @@ namespace Org.BouncyCastle.Crypto.Engines
private int processBlock128(byte[] input, int inOff, byte[] output, int outOff)
{
+ uint[] state = new uint[4];
+
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4));
- state[i] ^= kw[i];
+ state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -485,10 +485,11 @@ namespace Org.BouncyCastle.Crypto.Engines
private int processBlock192or256(byte[] input, int inOff, byte[] output, int outOff)
{
+ uint[] state = new uint[4];
+
for (int i = 0; i < 4; i++)
{
- state[i] = bytes2uint(input, inOff + (i * 4));
- state[i] ^= kw[i];
+ state[i] = bytes2uint(input, inOff + (i * 4)) ^ kw[i];
}
camelliaF2(state, subkey, 0);
@@ -516,6 +517,7 @@ namespace Org.BouncyCastle.Crypto.Engines
uint2bytes(state[3], output, outOff + 4);
uint2bytes(state[0], output, outOff + 8);
uint2bytes(state[1], output, outOff + 12);
+
return BLOCK_SIZE;
}
diff --git a/crypto/src/crypto/engines/SEEDEngine.cs b/crypto/src/crypto/engines/SEEDEngine.cs
index f615b8476..d4142c867 100644
--- a/crypto/src/crypto/engines/SEEDEngine.cs
+++ b/crypto/src/crypto/engines/SEEDEngine.cs
@@ -240,6 +240,9 @@ namespace Org.BouncyCastle.Crypto.Engines
private int[] createWorkingKey(
byte[] inKey)
{
+ if (inKey.Length != 16)
+ throw new ArgumentException("key size must be 128 bits");
+
int[] key = new int[32];
long lower = bytesToLong(inKey, 0);
long upper = bytesToLong(inKey, 8);
diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
index 9b8a956f2..33fabc8aa 100644
--- a/crypto/src/openpgp/PgpPublicKey.cs
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -460,7 +460,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
/// <summary>True, if this could be a master key.</summary>
public bool IsMasterKey
{
- get { return (subSigs == null) && !(this.IsEncryptionKey && publicPk.Algorithm != PublicKeyAlgorithmTag.RsaGeneral); }
+ get
+ {
+ // this might seem a bit excessive, but we're also trying to flag something can't be a master key.
+ return !(publicPk is PublicSubkeyPacket)
+ && !(this.IsEncryptionKey && publicPk.Algorithm != PublicKeyAlgorithmTag.RsaGeneral);
+ }
}
/// <summary>The algorithm code associated with the public key.</summary>
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index fd5ab6232..fcc4f672c 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -1,8 +1,12 @@
using System;
+using System.Collections;
using System.IO;
using System.Text;
using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.EdEC;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
@@ -16,6 +20,37 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
/// <remarks>Basic utility class.</remarks>
public sealed class PgpUtilities
{
+ private static IDictionary NameToHashID = CreateNameToHashID();
+ private static IDictionary OidToName = CreateOidToName();
+
+ private static IDictionary CreateNameToHashID()
+ {
+ IDictionary d = Platform.CreateHashtable();
+ d.Add("sha1", HashAlgorithmTag.Sha1);
+ d.Add("sha224", HashAlgorithmTag.Sha224);
+ d.Add("sha256", HashAlgorithmTag.Sha256);
+ d.Add("sha384", HashAlgorithmTag.Sha384);
+ d.Add("sha512", HashAlgorithmTag.Sha512);
+ d.Add("ripemd160", HashAlgorithmTag.RipeMD160);
+ d.Add("rmd160", HashAlgorithmTag.RipeMD160);
+ d.Add("md2", HashAlgorithmTag.MD2);
+ d.Add("tiger", HashAlgorithmTag.Tiger192);
+ d.Add("haval", HashAlgorithmTag.Haval5pass160);
+ d.Add("md5", HashAlgorithmTag.MD5);
+ return d;
+ }
+
+ private static IDictionary CreateOidToName()
+ {
+ IDictionary d = Platform.CreateHashtable();
+ d.Add(EdECObjectIdentifiers.id_X25519, "Curve25519");
+ d.Add(EdECObjectIdentifiers.id_Ed25519, "Ed25519");
+ d.Add(SecObjectIdentifiers.SecP256r1, "NIST P-256");
+ d.Add(SecObjectIdentifiers.SecP384r1, "NIST P-384");
+ d.Add(SecObjectIdentifiers.SecP521r1, "NIST P-521");
+ return d;
+ }
+
private PgpUtilities()
{
}
@@ -75,7 +110,32 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
}
}
- public static string GetSignatureName(
+ public static int GetDigestIDForName(string name)
+ {
+ name = Platform.ToLowerInvariant(name);
+ if (NameToHashID.Contains(name))
+ return (Int32)NameToHashID[name];
+
+ throw new ArgumentException("unable to map " + name + " to a hash id", "name");
+ }
+
+ /**
+ * Return the EC curve name for the passed in OID.
+ *
+ * @param oid the EC curve object identifier in the PGP key
+ * @return a string representation of the OID.
+ */
+ public static string GetCurveName(DerObjectIdentifier oid)
+ {
+ string name = (string)OidToName[oid];
+ if (name != null)
+ return name;
+
+ // fall back
+ return ECNamedCurveTable.GetName(oid);
+ }
+
+ public static string GetSignatureName(
PublicKeyAlgorithmTag keyAlgorithm,
HashAlgorithmTag hashAlgorithm)
{
|