From d003833c807b7d2f3951e4a4fb3ebc3a466418ed Mon Sep 17 00:00:00 2001 From: Carlos Perez Date: Sun, 8 Jun 2014 19:48:06 -0400 Subject: Add support to specifying Hash Algo when adding a subkey and generating a keyring. DSA2 and in the future EC keys requiere hashing higher than SHA1. --- crypto/src/bcpg/ArmoredOutputStream.cs | 51 +++++++++++++++-- crypto/src/openpgp/PgpKeyRingGenerator.cs | 95 +++++++++++++++++++++++++++++++ crypto/src/openpgp/PgpPublicKeyRing.cs | 1 + crypto/src/openpgp/PgpSecretKey.cs | 54 ++++++++++++++++++ 4 files changed, 195 insertions(+), 6 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs index b3a32c6f5..02d3f72a0 100644 --- a/crypto/src/bcpg/ArmoredOutputStream.cs +++ b/crypto/src/bcpg/ArmoredOutputStream.cs @@ -313,18 +313,57 @@ namespace Org.BouncyCastle.Bcpg } } - private void WriteHeaderEntry( - string name, - string v) + protected override void Dispose(bool disposing) + { + try + { + if (type != null) + { + if (bufPtr > 0) + { + Encode(outStream, buf, bufPtr); + } + + DoWrite(nl + '='); + + int crcV = crc.Value; + + buf[0] = ((crcV >> 16) & 0xff); + buf[1] = ((crcV >> 8) & 0xff); + buf[2] = (crcV & 0xff); + + Encode(outStream, buf, 3); + + DoWrite(nl); + DoWrite(footerStart); + DoWrite(type); + DoWrite(footerTail); + DoWrite(nl); + + outStream.Flush(); + + type = null; + start = true; + } + } + finally + { + base.Dispose(disposing); + } + } + + private void WriteHeaderEntry( + string name, + string v) { DoWrite(name + ": " + v + nl); } - private void DoWrite( - string s) + private void DoWrite( + string s) { byte[] bs = Strings.ToAsciiByteArray(s); - outStream.Write(bs, 0, bs.Length); + outStream.Write(bs, 0, bs.Length); } } } diff --git a/crypto/src/openpgp/PgpKeyRingGenerator.cs b/crypto/src/openpgp/PgpKeyRingGenerator.cs index e85fc2eef..92ea394a2 100644 --- a/crypto/src/openpgp/PgpKeyRingGenerator.cs +++ b/crypto/src/openpgp/PgpKeyRingGenerator.cs @@ -15,6 +15,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp private IList keys = Platform.CreateArrayList(); private string id; private SymmetricKeyAlgorithmTag encAlgorithm; + private HashAlgorithmTag hashAlgorithm; private int certificationLevel; private char[] passPhrase; private bool useSha1; @@ -84,6 +85,45 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); } + /// + /// Create a new key ring generator. + /// + /// The certification level for keys on this ring. + /// The master key pair. + /// The id to be associated with the ring. + /// The algorithm to be used to protect secret keys. + /// The hash algorithm. + /// The passPhrase to be used to protect secret keys. + /// Checksum the secret keys with SHA1 rather than the older 16 bit checksum. + /// Packets to be included in the certification hash. + /// Packets to be attached unhashed to the certification. + /// input secured random. + public PgpKeyRingGenerator( + int certificationLevel, + PgpKeyPair masterKey, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + HashAlgorithmTag hashAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + { + this.certificationLevel = certificationLevel; + this.masterKey = masterKey; + this.id = id; + this.encAlgorithm = encAlgorithm; + this.passPhrase = passPhrase; + this.useSha1 = useSha1; + this.hashedPacketVector = hashedPackets; + this.unhashedPacketVector = unhashedPackets; + this.rand = rand; + this.hashAlgorithm = hashAlgorithm; + + keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)); + } + /// Add a subkey to the key ring to be generated with default certification. public void AddSubKey( PgpKeyPair keyPair) @@ -91,6 +131,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector); } + + /// + /// Add a subkey to the key ring to be generated with default certification. + /// + /// The key pair. + /// The hash algorithm. + public void AddSubKey(PgpKeyPair keyPair, HashAlgorithmTag hashAlgorithm) + { + this.AddSubKey(keyPair, this.hashedPacketVector, this.unhashedPacketVector, hashAlgorithm); + } + /// /// Add a subkey with specific hashed and unhashed packets associated with it and /// default certification. @@ -133,6 +184,50 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + /// + /// Add a subkey with specific hashed and unhashed packets associated with it and + /// default certification. + /// + /// Public/private key pair. + /// Hashed packet values to be included in certification. + /// Unhashed packets values to be included in certification. + /// The hash algorithm. + /// exception adding subkey: + /// + public void AddSubKey( + PgpKeyPair keyPair, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + HashAlgorithmTag hashAlgorithm) + { + try + { + var sGen = new PgpSignatureGenerator(masterKey.PublicKey.Algorithm, hashAlgorithm); + + // + // Generate the certification + // + sGen.InitSign(PgpSignature.SubkeyBinding, masterKey.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + IList subSigs = Platform.CreateArrayList(); + subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey)); + + keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm, passPhrase, useSha1, rand)); + } + catch (PgpException) + { + throw; + } + catch (Exception e) + { + throw new PgpException("exception adding subkey: ", e); + } + } + + /// Return the secret key ring. public PgpSecretKeyRing GenerateSecretKeyRing() { diff --git a/crypto/src/openpgp/PgpPublicKeyRing.cs b/crypto/src/openpgp/PgpPublicKeyRing.cs index ecb935e4b..0f5e04516 100644 --- a/crypto/src/openpgp/PgpPublicKeyRing.cs +++ b/crypto/src/openpgp/PgpPublicKeyRing.cs @@ -169,6 +169,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp PgpPublicKeyRing pubRing, PgpPublicKey pubKey) { + IList keys = Platform.CreateArrayList(pubRing.keys); bool found = false; diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs index 872316dd7..84d23614f 100644 --- a/crypto/src/openpgp/PgpSecretKey.cs +++ b/crypto/src/openpgp/PgpSecretKey.cs @@ -158,6 +158,21 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp { } + public PgpSecretKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + SymmetricKeyAlgorithmTag encAlgorithm, + HashAlgorithmTag hashAlgorithm, + char[] passPhrase, + bool useSha1, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + SecureRandom rand) + : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm), encAlgorithm, passPhrase, useSha1, rand, true) + { + } + private static PgpPublicKey CertifiedPublicKey( int certificationLevel, PgpKeyPair keyPair, @@ -194,6 +209,44 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp } } + + private static PgpPublicKey CertifiedPublicKey( + int certificationLevel, + PgpKeyPair keyPair, + string id, + PgpSignatureSubpacketVector hashedPackets, + PgpSignatureSubpacketVector unhashedPackets, + HashAlgorithmTag hashAlgorithm) + { + PgpSignatureGenerator sGen; + try + { + sGen = new PgpSignatureGenerator(keyPair.PublicKey.Algorithm, hashAlgorithm); + } + catch (Exception e) + { + throw new PgpException("Creating signature generator: " + e.Message, e); + } + + // + // Generate the certification + // + sGen.InitSign(certificationLevel, keyPair.PrivateKey); + + sGen.SetHashedSubpackets(hashedPackets); + sGen.SetUnhashedSubpackets(unhashedPackets); + + try + { + PgpSignature certification = sGen.GenerateCertification(id, keyPair.PublicKey); + return PgpPublicKey.AddCertification(keyPair.PublicKey, id, certification); + } + catch (Exception e) + { + throw new PgpException("Exception doing certification: " + e.Message, e); + } + } + public PgpSecretKey( int certificationLevel, PublicKeyAlgorithmTag algorithm, @@ -585,6 +638,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { + if (key.IsPrivateKeyEmpty) throw new PgpException("no private key in this SecretKey - public key present only."); -- cgit 1.5.1 From 5f892454e860c44e27979d635a75350da99e675d Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sat, 17 Oct 2015 13:20:15 +0700 Subject: Fix whitespace and remove Dispose method --- crypto/src/bcpg/ArmoredOutputStream.cs | 145 ++++++++++++--------------------- crypto/src/openpgp/PgpPublicKeyRing.cs | 1 - 2 files changed, 53 insertions(+), 93 deletions(-) (limited to 'crypto/src') diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs index 02d3f72a0..5d4b6b5a7 100644 --- a/crypto/src/bcpg/ArmoredOutputStream.cs +++ b/crypto/src/bcpg/ArmoredOutputStream.cs @@ -36,46 +36,46 @@ namespace Org.BouncyCastle.Bcpg * encode the input data producing a base 64 encoded byte array. */ private static void Encode( - Stream outStream, - int[] data, - int len) + Stream outStream, + int[] data, + int len) { - Debug.Assert(len > 0); - Debug.Assert(len < 4); + Debug.Assert(len > 0); + Debug.Assert(len < 4); - byte[] bs = new byte[4]; - int d1 = data[0]; - bs[0] = encodingTable[(d1 >> 2) & 0x3f]; + byte[] bs = new byte[4]; + int d1 = data[0]; + bs[0] = encodingTable[(d1 >> 2) & 0x3f]; - switch (len) + switch (len) { - case 1: - { - bs[1] = encodingTable[(d1 << 4) & 0x3f]; - bs[2] = (byte)'='; - bs[3] = (byte)'='; - break; - } - case 2: - { - int d2 = data[1]; - bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; - bs[2] = encodingTable[(d2 << 2) & 0x3f]; - bs[3] = (byte)'='; - break; - } - case 3: - { - int d2 = data[1]; - int d3 = data[2]; - bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; - bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f]; - bs[3] = encodingTable[d3 & 0x3f]; - break; - } + case 1: + { + bs[1] = encodingTable[(d1 << 4) & 0x3f]; + bs[2] = (byte)'='; + bs[3] = (byte)'='; + break; + } + case 2: + { + int d2 = data[1]; + bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; + bs[2] = encodingTable[(d2 << 2) & 0x3f]; + bs[3] = (byte)'='; + break; + } + case 3: + { + int d2 = data[1]; + int d3 = data[2]; + bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f]; + bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f]; + bs[3] = encodingTable[d3 & 0x3f]; + break; + } } - outStream.Write(bs, 0, bs.Length); + outStream.Write(bs, 0, bs.Length); } private readonly Stream outStream; @@ -91,18 +91,18 @@ namespace Org.BouncyCastle.Bcpg private string type; - private static readonly string nl = Platform.NewLine; - private static readonly string headerStart = "-----BEGIN PGP "; - private static readonly string headerTail = "-----"; - private static readonly string footerStart = "-----END PGP "; - private static readonly string footerTail = "-----"; + private static readonly string nl = Platform.NewLine; + private static readonly string headerStart = "-----BEGIN PGP "; + private static readonly string headerTail = "-----"; + private static readonly string footerStart = "-----END PGP "; + private static readonly string footerTail = "-----"; private static readonly string version = "BCPG C# v" - + Assembly.GetExecutingAssembly().GetName().Version; + + Assembly.GetExecutingAssembly().GetName().Version; - private readonly IDictionary headers; + private readonly IDictionary headers; - public ArmoredOutputStream(Stream outStream) + public ArmoredOutputStream(Stream outStream) { this.outStream = outStream; this.headers = Platform.CreateHashtable(); @@ -174,10 +174,10 @@ namespace Org.BouncyCastle.Bcpg throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm); } - DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); + DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl); DoWrite("Hash: " + hash + nl + nl); - clearText = true; + clearText = true; newLine = true; lastb = 0; } @@ -218,7 +218,7 @@ namespace Org.BouncyCastle.Bcpg { bool newPacket = (b & 0x40) != 0; - int tag; + int tag; if (newPacket) { tag = b & 0x3f; @@ -241,7 +241,7 @@ namespace Org.BouncyCastle.Bcpg break; default: type = "MESSAGE"; - break; + break; } DoWrite(headerStart + type + headerTail + nl); @@ -277,23 +277,23 @@ namespace Org.BouncyCastle.Bcpg } /** - * Note: close does nor close the underlying stream. So it is possible to write + * Note: Close() does not close the underlying stream. So it is possible to write * multiple objects using armoring to a single stream. */ public override void Close() { if (type != null) { - if (bufPtr > 0) - { - Encode(outStream, buf, bufPtr); - } + if (bufPtr > 0) + { + Encode(outStream, buf, bufPtr); + } DoWrite(nl + '='); int crcV = crc.Value; - buf[0] = ((crcV >> 16) & 0xff); + buf[0] = ((crcV >> 16) & 0xff); buf[1] = ((crcV >> 8) & 0xff); buf[2] = (crcV & 0xff); @@ -309,46 +309,7 @@ namespace Org.BouncyCastle.Bcpg type = null; start = true; - base.Close(); - } - } - - protected override void Dispose(bool disposing) - { - try - { - if (type != null) - { - if (bufPtr > 0) - { - Encode(outStream, buf, bufPtr); - } - - DoWrite(nl + '='); - - int crcV = crc.Value; - - buf[0] = ((crcV >> 16) & 0xff); - buf[1] = ((crcV >> 8) & 0xff); - buf[2] = (crcV & 0xff); - - Encode(outStream, buf, 3); - - DoWrite(nl); - DoWrite(footerStart); - DoWrite(type); - DoWrite(footerTail); - DoWrite(nl); - - outStream.Flush(); - - type = null; - start = true; - } - } - finally - { - base.Dispose(disposing); + base.Close(); } } diff --git a/crypto/src/openpgp/PgpPublicKeyRing.cs b/crypto/src/openpgp/PgpPublicKeyRing.cs index 592ca86c8..7b1ac93bf 100644 --- a/crypto/src/openpgp/PgpPublicKeyRing.cs +++ b/crypto/src/openpgp/PgpPublicKeyRing.cs @@ -169,7 +169,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp PgpPublicKeyRing pubRing, PgpPublicKey pubKey) { - IList keys = Platform.CreateArrayList(pubRing.keys); bool found = false; -- cgit 1.5.1