Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial implementation of OpenPGP EdDSA and usage of the Curve25519 in ECDH #282

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crypto/BouncyCastle.Android.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,7 @@
<Compile Include="src\crypto\signers\Ed25519Signer.cs" />
<Compile Include="src\crypto\signers\Ed448phSigner.cs" />
<Compile Include="src\crypto\signers\Ed448Signer.cs" />
<Compile Include="src\crypto\signers\EdDsa25519Signer.cs" />
<Compile Include="src\crypto\signers\GOST3410DigestSigner.cs" />
<Compile Include="src\crypto\signers\GOST3410Signer.cs" />
<Compile Include="src\crypto\signers\GenericSigner.cs" />
Expand Down Expand Up @@ -1486,7 +1487,8 @@
<Compile Include="src\openpgp\PgpUtilities.cs" />
<Compile Include="src\openpgp\PgpV3SignatureGenerator.cs" />
<Compile Include="src\openpgp\Rfc6637Utilities.cs" />
<Compile Include="src\openpgp\SXprUtilities.cs" />
<Compile Include="src\openpgp\SXprReader.cs" />
<Compile Include="src\openpgp\SXprWriter.cs" />
<Compile Include="src\openpgp\WrappedGeneratorStream.cs" />
<Compile Include="src\openssl\EncryptionException.cs" />
<Compile Include="src\openssl\IPasswordFinder.cs" />
Expand Down
4 changes: 3 additions & 1 deletion crypto/BouncyCastle.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@
<Compile Include="src\crypto\signers\Ed25519Signer.cs" />
<Compile Include="src\crypto\signers\Ed448phSigner.cs" />
<Compile Include="src\crypto\signers\Ed448Signer.cs" />
<Compile Include="src\crypto\signers\EdDsa25519Signer.cs" />
<Compile Include="src\crypto\signers\GOST3410DigestSigner.cs" />
<Compile Include="src\crypto\signers\GOST3410Signer.cs" />
<Compile Include="src\crypto\signers\GenericSigner.cs" />
Expand Down Expand Up @@ -1480,7 +1481,8 @@
<Compile Include="src\openpgp\PgpUtilities.cs" />
<Compile Include="src\openpgp\PgpV3SignatureGenerator.cs" />
<Compile Include="src\openpgp\Rfc6637Utilities.cs" />
<Compile Include="src\openpgp\SXprUtilities.cs" />
<Compile Include="src\openpgp\SXprReader.cs" />
<Compile Include="src\openpgp\SXprWriter.cs" />
<Compile Include="src\openpgp\WrappedGeneratorStream.cs" />
<Compile Include="src\openssl\EncryptionException.cs" />
<Compile Include="src\openssl\IPasswordFinder.cs" />
Expand Down
4 changes: 3 additions & 1 deletion crypto/BouncyCastle.iOS.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,7 @@
<Compile Include="src\crypto\signers\Ed25519Signer.cs" />
<Compile Include="src\crypto\signers\Ed448phSigner.cs" />
<Compile Include="src\crypto\signers\Ed448Signer.cs" />
<Compile Include="src\crypto\signers\EdDsa25519Signer.cs" />
<Compile Include="src\crypto\signers\GOST3410DigestSigner.cs" />
<Compile Include="src\crypto\signers\GOST3410Signer.cs" />
<Compile Include="src\crypto\signers\GenericSigner.cs" />
Expand Down Expand Up @@ -1481,7 +1482,8 @@
<Compile Include="src\openpgp\PgpUtilities.cs" />
<Compile Include="src\openpgp\PgpV3SignatureGenerator.cs" />
<Compile Include="src\openpgp\Rfc6637Utilities.cs" />
<Compile Include="src\openpgp\SXprUtilities.cs" />
<Compile Include="src\openpgp\SXprReader.cs" />
<Compile Include="src\openpgp\SXprWriter.cs" />
<Compile Include="src\openpgp\WrappedGeneratorStream.cs" />
<Compile Include="src\openssl\EncryptionException.cs" />
<Compile Include="src\openssl\IPasswordFinder.cs" />
Expand Down
12 changes: 11 additions & 1 deletion crypto/crypto.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5143,6 +5143,11 @@
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "src\crypto\signers\EdDsa25519Signer.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "src\crypto\signers\GenericSigner.cs"
SubType = "Code"
Expand Down Expand Up @@ -7289,7 +7294,12 @@
BuildAction = "Compile"
/>
<File
RelPath = "src\openpgp\SXprUtilities.cs"
RelPath = "src\openpgp\SXprReader.cs"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "src\openpgp\SXprWriter.cs"
SubType = "Code"
BuildAction = "Compile"
/>
Expand Down
6 changes: 3 additions & 3 deletions crypto/src/asn1/gnu/GNUObjectIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public abstract class GnuObjectIdentifiers
public static readonly DerObjectIdentifier Crc = new DerObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
public static readonly DerObjectIdentifier Crc32 = new DerObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32

/** 1.3.6.1.4.1.11591.15 - ellipticCurve */
public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.6.1.4.1.11591.15");
/** 1.3.6.1.4.1.11591.15 - ellipticCurve */
public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier("1.3.6.1.4.1.11591.15");

public static readonly DerObjectIdentifier Ed25519 = EllipticCurve.Branch("1");
public static readonly DerObjectIdentifier Ed25519 = EllipticCurve.Branch("1");
}
}
3 changes: 3 additions & 0 deletions crypto/src/asn1/misc/MiscObjectIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ public abstract class MiscObjectIdentifiers
public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.Branch("1.3");
public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.Branch("1.4");

// OpenPGP (draft-ietf-openpgp-rfc4880bis-10)
public static readonly DerObjectIdentifier Curve25519 = cryptlib_algorithm.Branch("5.1");

//
// Blake2b
//
Expand Down
16 changes: 16 additions & 0 deletions crypto/src/bcpg/ECDHPublicBCPGKey.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;

namespace Org.BouncyCastle.Bcpg
Expand Down Expand Up @@ -48,6 +49,21 @@ public ECDHPublicBcpgKey(
VerifySymmetricKeyAlgorithm();
}

public ECDHPublicBcpgKey(
DerObjectIdentifier oid,
BigInteger encodedPoint,
HashAlgorithmTag hashAlgorithm,
SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
: base(oid, encodedPoint)
{
reserved = 1;
hashFunctionId = hashAlgorithm;
symAlgorithmId = symmetricKeyAlgorithm;

VerifyHashAlgorithm();
VerifySymmetricKeyAlgorithm();
}

public virtual byte Reserved
{
get { return reserved; }
Expand Down
1 change: 1 addition & 0 deletions crypto/src/bcpg/PublicKeyPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ internal PublicKeyPacket(
key = new ECDHPublicBcpgKey(bcpgIn);
break;
case PublicKeyAlgorithmTag.ECDsa:
case PublicKeyAlgorithmTag.EdDsa:
key = new ECDsaPublicBcpgKey(bcpgIn);
break;
default:
Expand Down
1 change: 1 addition & 0 deletions crypto/src/bcpg/SignaturePacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ internal SignaturePacket(
signature = new MPInteger[]{ p, g, y };
break;
case PublicKeyAlgorithmTag.ECDsa:
case PublicKeyAlgorithmTag.EdDsa:
MPInteger ecR = new MPInteger(bcpgIn);
MPInteger ecS = new MPInteger(bcpgIn);
signature = new MPInteger[]{ ecR, ecS };
Expand Down
5 changes: 4 additions & 1 deletion crypto/src/crypto/ec/CustomNamedCurves.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.GM;
using Org.BouncyCastle.Asn1.Gnu;
using Org.BouncyCastle.Asn1.Misc;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Math;
Expand Down Expand Up @@ -789,7 +791,8 @@ private static void DefineCurveAlias(string name, DerObjectIdentifier oid)

static CustomNamedCurves()
{
DefineCurve("curve25519", Curve25519Holder.Instance);
DefineCurveWithOid("ed25519", GnuObjectIdentifiers.Ed25519, Curve25519Holder.Instance);
DefineCurveWithOid("curve25519", MiscObjectIdentifiers.Curve25519, Curve25519Holder.Instance);

//DefineCurveWithOid("secp112r1", SecObjectIdentifiers.SecP112r1, SecP112R1Holder.Instance);
//DefineCurveWithOid("secp112r2", SecObjectIdentifiers.SecP112r2, SecP112R2Holder.Instance);
Expand Down
47 changes: 47 additions & 0 deletions crypto/src/crypto/signers/EdDsa25519Signer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;

using Org.BouncyCastle.Math;

namespace Org.BouncyCastle.Crypto.Signers
{
public class EdDsa22519Signer : IDsa
{
private Ed25519Signer signer;

public virtual string AlgorithmName => "EDDSA";

public EdDsa22519Signer()
{
signer = new Ed25519Signer();
}

public virtual void Init(bool forSigning, ICipherParameters parameters)
{
signer.Init(forSigning, parameters);
}

public virtual BigInteger[] GenerateSignature(byte[] message)
{
signer.BlockUpdate(message, 0, message.Length);
byte[] sigBytes = signer.GenerateSignature();
byte[] rBytes = new byte[32];
Array.Copy(sigBytes, rBytes, 32);
byte[] sBytes = new byte[sigBytes.Length - 32];
Array.Copy(sigBytes, 32, sBytes, 0, sigBytes.Length - 32);
BigInteger r = new BigInteger(1, rBytes);
BigInteger s = new BigInteger(1, sBytes);
return new BigInteger[2] { r, s };
}

public virtual bool VerifySignature(byte[] message, BigInteger r, BigInteger s)
{
signer.BlockUpdate(message, 0, message.Length);
byte[] rBytes = r.ToByteArrayUnsigned();
byte[] sBytes = s.ToByteArrayUnsigned();
byte[] sigBytes = new byte[64];
Array.Copy(rBytes, 0, sigBytes, 32 - rBytes.Length, rBytes.Length);
Array.Copy(sBytes, 0, sigBytes, 64 - sBytes.Length, sBytes.Length);
return signer.VerifySignature(sigBytes);
}
}
}
50 changes: 37 additions & 13 deletions crypto/src/openpgp/PgpEncryptedDataGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
using System.Diagnostics;
using System.IO;

using Org.BouncyCastle.Asn1.Misc;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.IO;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Rfc7748;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;

Expand Down Expand Up @@ -102,10 +104,12 @@ public override void AddSessionInfo(

private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
{
AsymmetricKeyParameter akp = pubKey.GetKey();

if (pubKey.Algorithm != PublicKeyAlgorithmTag.ECDH)
{
IBufferedCipher c;
switch (pubKey.Algorithm)
switch (pubKey.Algorithm)
{
case PublicKeyAlgorithmTag.RsaEncrypt:
case PublicKeyAlgorithmTag.RsaGeneral:
Expand All @@ -119,37 +123,57 @@ private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
throw new PgpException("Can't use DSA for encryption.");
case PublicKeyAlgorithmTag.ECDsa:
throw new PgpException("Can't use ECDSA for encryption.");
case PublicKeyAlgorithmTag.EdDsa:
throw new PgpException("Can't use EdDSA for encryption.");
default:
throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
}

AsymmetricKeyParameter akp = pubKey.GetKey();
c.Init(true, new ParametersWithRandom(akp, random));
c.Init(true, new ParametersWithRandom(akp, random));
return c.DoFinal(sessionInfo);
}

ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key;
KeyParameter key;
byte[] encodedPublicKey;

// Generate the ephemeral key pair
IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH");
gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random));
if (akp is X25519PublicKeyParameters)
{
X25519PublicKeyParameters pub = (X25519PublicKeyParameters)akp;
byte[] privateKey = new byte[X25519.PointSize];
X25519.GeneratePrivateKey(random, privateKey);
byte[] sharedKey = new byte[32];
X25519.CalculateAgreement(privateKey, 0, pub.GetEncoded(), 0, sharedKey, 0);
byte[] publicKey = new byte[X25519.PointSize + 1];
publicKey[0] = 0x40; // compressed point
X25519.GeneratePublicKey(privateKey, 0, publicKey, 1);
encodedPublicKey = publicKey;
key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, sharedKey));
}
else
{
// Generate the ephemeral key pair
IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH");
gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random));

AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair();
ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private;
ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public;
AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair();
ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private;
ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public;

ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey.GetKey();
ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize();
ECPublicKeyParameters pub = (ECPublicKeyParameters)akp;
ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize();

KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S));
key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S));
encodedPublicKey = ephPub.Q.GetEncoded(false);
}

IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
w.Init(true, new ParametersWithRandom(key, random));

byte[] paddedSessionData = PgpPad.PadSessionData(sessionInfo, sessionKeyObfuscation);

byte[] C = w.Wrap(paddedSessionData, 0, paddedSessionData.Length);
byte[] VB = new MPInteger(new BigInteger(1, ephPub.Q.GetEncoded(false))).GetEncoded();
byte[] VB = new MPInteger(new BigInteger(1, encodedPublicKey)).GetEncoded();

byte[] rv = new byte[VB.Length + 1 + C.Length];

Expand Down
39 changes: 37 additions & 2 deletions crypto/src/openpgp/PgpPublicKey.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System;
using System.Collections;
using System.IO;

using Org.BouncyCastle.Asn1.Gnu;
using Org.BouncyCastle.Asn1.Misc;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
Expand All @@ -10,6 +11,8 @@
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Math.EC.Rfc7748;
using Org.BouncyCastle.Math.EC.Rfc8032;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Collections;
Expand Down Expand Up @@ -177,11 +180,35 @@ public PgpPublicKey(
{
bcpgKey = new ECDsaPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q);
}
else if (algorithm == PublicKeyAlgorithmTag.EdDsa)
{
bcpgKey = new ECDsaPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q);
}
else
{
throw new PgpException("unknown EC algorithm");
}
}
else if (pubKey is Ed25519PublicKeyParameters)
{
Ed25519PublicKeyParameters ecK = (Ed25519PublicKeyParameters)pubKey;
byte[] encodedPoint = new byte[Ed25519.PublicKeySize + 1];
encodedPoint[0] = 0x40;
ecK.Encode(encodedPoint, 1);
bcpgKey = new ECDsaPublicBcpgKey(GnuObjectIdentifiers.Ed25519, new BigInteger(1, encodedPoint));
}
else if (pubKey is X25519PublicKeyParameters)
{
X25519PublicKeyParameters ecK = (X25519PublicKeyParameters)pubKey;
byte[] encodedPoint = new byte[X25519.PointSize + 1];
encodedPoint[0] = 0x40;
ecK.Encode(encodedPoint, 1);
bcpgKey = new ECDHPublicBcpgKey(
MiscObjectIdentifiers.Curve25519,
new BigInteger(1, encodedPoint),
HashAlgorithmTag.Sha256,
SymmetricKeyAlgorithmTag.Aes128);
}
else if (pubKey is ElGamalPublicKeyParameters)
{
ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
Expand Down Expand Up @@ -495,7 +522,15 @@ public AsymmetricKeyParameter GetKey()
case PublicKeyAlgorithmTag.ECDsa:
return GetECKey("ECDSA");
case PublicKeyAlgorithmTag.ECDH:
return GetECKey("ECDH");
if (((ECPublicBcpgKey)publicPk.Key).CurveOid.Id.Equals(MiscObjectIdentifiers.Curve25519.Id))
{
byte[] encodedPoint = ((ECPublicBcpgKey)publicPk.Key).EncodedPoint.ToByteArrayUnsigned();
return new X25519PublicKeyParameters(encodedPoint, 1);
}
else
return GetECKey("ECDH");
case PublicKeyAlgorithmTag.EdDsa:
return new Ed25519PublicKeyParameters(((ECPublicBcpgKey)publicPk.Key).EncodedPoint.ToByteArrayUnsigned(), 1);
case PublicKeyAlgorithmTag.ElGamalEncrypt:
case PublicKeyAlgorithmTag.ElGamalGeneral:
ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key;
Expand Down
Loading