/// <summary>Replace the passed the public key on the passed in secret key.</summary> /// <param name="secretKey">Secret key to change.</param> /// <param name="publicKey">New public key.</param> /// <returns>A new secret key.</returns> /// <exception cref="ArgumentException">If KeyId's do not match.</exception> public static PgpSecretKey ReplacePublicKey( PgpSecretKey secretKey, PgpPublicKey publicKey) { if (publicKey.KeyId != secretKey.KeyId) { throw new ArgumentException("KeyId's do not match"); } return(new PgpSecretKey(secretKey.secret, publicKey)); }
/// <summary> /// Initializes a new instance of the EncryptionKeys class. /// Two keys are required to encrypt and sign data. Your private key and the recipients public key. /// The data is encrypted with the recipients public key and signed with your private key. /// </summary> /// <param name="publicKeyPath">The key used to encrypt the data</param> /// <param name="privateKeyPath">The key used to sign the data.</param> /// <param name="passPhrase">The (your) password required to access the private key</param> /// <exception cref="ArgumentException">Public key not found. Private key not found. Missing password</exception> public PgpEncryptionKeys(string publicKeyPath, string privateKeyPath, string passPhrase) { if (!File.Exists(publicKeyPath)) throw new ArgumentException("Public key file not found", "publicKeyPath"); if (!File.Exists(privateKeyPath)) throw new ArgumentException("Private key file not found", "privateKeyPath"); if (String.IsNullOrEmpty(passPhrase)) throw new ArgumentException("passPhrase is null or empty.", "passPhrase"); PublicKey = ReadPublicKey(publicKeyPath); SecretKey = ReadSecretKey(privateKeyPath); PrivateKey = ReadPrivateKey(passPhrase); }
/// <summary> /// Replace the public key set on the secret ring with the corresponding key off the public ring. /// </summary> /// <param name="secretRing">Secret ring to be changed.</param> /// <param name="publicRing">Public ring containing the new public key set.</param> public static PgpSecretKeyRing ReplacePublicKeys(PgpSecretKeyRing secretRing, PgpPublicKeyRing publicRing) { var newList = Platform.CreateArrayList(secretRing.SecretKeyCount); foreach (PgpSecretKey sk in secretRing.GetSecretKeys()) { var pk = publicRing.GetPublicKey(sk.KeyId); newList.Add(PgpSecretKey.ReplacePublicKey(sk, pk)); } return(new PgpSecretKeyRing(newList)); }
internal static PgpSecretKey DoCopyWithNewPassword(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, bool clearPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { if (key.IsPrivateKeyEmpty) { throw new PgpException("no private key in this SecretKey - public key present only."); } byte[] array = key.ExtractKeyData(rawOldPassPhrase, clearPassPhrase); int num = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; PublicKeyPacket publicKeyPacket = key.secret.PublicKeyPacket; byte[] array2; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { num = 0; if (key.secret.S2kUsage == 254) { array2 = new byte[array.Length - 18]; global::System.Array.Copy((global::System.Array)array, 0, (global::System.Array)array2, 0, array2.Length - 2); byte[] array3 = Checksum(useSha1: false, array2, array2.Length - 2); array2[array2.Length - 2] = array3[0]; array2[array2.Length - 1] = array3[1]; } else { array2 = array; } } else { if (num == 0) { num = 255; } try { array2 = ((publicKeyPacket.Version < 4) ? EncryptKeyDataV3(array, newEncAlgorithm, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv) : EncryptKeyDataV4(array, newEncAlgorithm, HashAlgorithmTag.Sha1, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv)); } catch (PgpException ex) { throw ex; } catch (global::System.Exception exception) { throw new PgpException("Exception encrypting key", exception); } } SecretKeyPacket secretKeyPacket = ((!(key.secret is SecretSubkeyPacket)) ? new SecretKeyPacket(publicKeyPacket, newEncAlgorithm, num, s2k, iv, array2) : new SecretSubkeyPacket(publicKeyPacket, newEncAlgorithm, num, s2k, iv, array2)); return(new PgpSecretKey(secretKeyPacket, key.pub)); }
/// <summary>Return the PGP secret key associated with the given key id.</summary> /// <param name="keyId">The ID of the secret key to return.</param> public PgpSecretKey GetSecretKey( long keyId) { foreach (PgpSecretKeyRing secRing in GetKeyRings()) { PgpSecretKey sec = secRing.GetSecretKey(keyId); if (sec != null) { return(sec); } } return(null); }
/// <summary> /// Return a copy of the passed in secret key ring, with the master key and sub keys encrypted /// using a new password and the passed in algorithm. /// </summary> /// <param name="ring">The <c>PgpSecretKeyRing</c> to be copied.</param> /// <param name="oldPassPhrase">The current password for key.</param> /// <param name="newPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKeyRing CopyWithNewPassword( PgpSecretKeyRing ring, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { IList newKeys = Platform.CreateArrayList(ring.keys.Count); foreach (PgpSecretKey secretKey in ring.GetSecretKeys()) { newKeys.Add(PgpSecretKey.CopyWithNewPassword(secretKey, oldPassPhrase, newPassPhrase, newEncAlgorithm, rand)); } return(new PgpSecretKeyRing(newKeys, ring.extraPubKeys)); }
public PgpPublicKeyRing GeneratePublicKeyRing() { global::System.Collections.IList list = Platform.CreateArrayList(); global::System.Collections.IEnumerator enumerator = ((global::System.Collections.IEnumerable)keys).GetEnumerator(); enumerator.MoveNext(); PgpSecretKey pgpSecretKey = (PgpSecretKey)enumerator.get_Current(); list.Add((object)pgpSecretKey.PublicKey); while (enumerator.MoveNext()) { pgpSecretKey = (PgpSecretKey)enumerator.get_Current(); PgpPublicKey pgpPublicKey = new PgpPublicKey(pgpSecretKey.PublicKey); pgpPublicKey.publicPk = new PublicSubkeyPacket(pgpPublicKey.Algorithm, pgpPublicKey.CreationTime, pgpPublicKey.publicPk.Key); list.Add((object)pgpPublicKey); } return(new PgpPublicKeyRing(list)); }
private static void ExportKeyPair( Stream secretOut, Stream publicOut, AsymmetricKeyParameter publicKey, AsymmetricKeyParameter privateKey, string identity, char[] passPhrase, bool armor) { if (armor) { secretOut = new ArmoredOutputStream(secretOut); } PgpSecretKey secretKey = new PgpSecretKey( PgpSignature.DefaultCertification, PublicKeyAlgorithmTag.RsaGeneral, publicKey, privateKey, DateTime.UtcNow, identity, SymmetricKeyAlgorithmTag.Cast5, passPhrase, null, null, new SecureRandom() ); secretKey.Encode(secretOut); if (armor) { secretOut.Close(); publicOut = new ArmoredOutputStream(publicOut); } PgpPublicKey key = secretKey.PublicKey; key.Encode(publicOut); if (armor) { publicOut.Close(); } }
/// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary> /// <param name="secRing">The secret key ring to be modified.</param> /// <param name="secKey">The secret key to be removed.</param> /// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns> public static PgpSecretKeyRing RemoveSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey) { var keys = Platform.CreateArrayList(secRing._keys); var found = false; for (var i = 0; i < keys.Count; i++) { var key = keys[i]; if (key.KeyId != secKey.KeyId) { continue; } found = true; keys.RemoveAt(i); } return(found ? new PgpSecretKeyRing(keys, secRing._extraPubKeys) : null); }
public void Encode(Stream outStr) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (outStr == null) { throw new ArgumentNullException("outStr"); } global::System.Collections.IEnumerator enumerator = ((global::System.Collections.IEnumerable)keys).GetEnumerator(); try { while (enumerator.MoveNext()) { PgpSecretKey pgpSecretKey = (PgpSecretKey)enumerator.get_Current(); pgpSecretKey.Encode(outStr); } } finally { global::System.IDisposable disposable = enumerator as global::System.IDisposable; if (disposable != null) { disposable.Dispose(); } } enumerator = ((global::System.Collections.IEnumerable)extraPubKeys).GetEnumerator(); try { while (enumerator.MoveNext()) { PgpPublicKey pgpPublicKey = (PgpPublicKey)enumerator.get_Current(); pgpPublicKey.Encode(outStr); } } finally { global::System.IDisposable disposable2 = enumerator as global::System.IDisposable; if (disposable2 != null) { disposable2.Dispose(); } } }
/// <summary> /// Returns a new key ring with the secret key passed in either added or /// replacing an existing one with the same key ID. /// </summary> /// <param name="secRing">The secret key ring to be modified.</param> /// <param name="secKey">The secret key to be inserted.</param> /// <returns>A new <c>PgpSecretKeyRing</c></returns> public static PgpSecretKeyRing InsertSecretKey( PgpSecretKeyRing secRing, PgpSecretKey secKey) { IList keys = Platform.CreateArrayList(secRing.keys); bool found = false; bool masterFound = false; for (int i = 0; i != keys.Count; i++) { PgpSecretKey key = (PgpSecretKey)keys[i]; if (key.KeyId == secKey.KeyId) { found = true; keys[i] = secKey; } if (key.IsMasterKey) { masterFound = true; } } if (!found) { if (secKey.IsMasterKey) { if (masterFound) { throw new ArgumentException("cannot add a master key to a ring that already has one"); } keys.Insert(0, secKey); } else { keys.Add(secKey); } } return(new PgpSecretKeyRing(keys, secRing.extraPubKeys)); }
/// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary> /// <param name="secRing">The secret key ring to be modified.</param> /// <param name="secKey">The secret key to be removed.</param> /// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns> public static PgpSecretKeyRing RemoveSecretKey( PgpSecretKeyRing secRing, PgpSecretKey secKey) { IList keys = Platform.CreateArrayList(secRing.keys); bool found = false; for (int i = 0; i < keys.Count; i++) { PgpSecretKey key = (PgpSecretKey)keys[i]; if (key.KeyId == secKey.KeyId) { found = true; keys.RemoveAt(i); } } return(found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null); }
public static PgpSecretKeyRing RemoveSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey) { global::System.Collections.IList list = Platform.CreateArrayList((global::System.Collections.ICollection)secRing.keys); bool flag = false; for (int i = 0; i < ((global::System.Collections.ICollection)list).get_Count(); i++) { PgpSecretKey pgpSecretKey = (PgpSecretKey)list.get_Item(i); if (pgpSecretKey.KeyId == secKey.KeyId) { flag = true; list.RemoveAt(i); } } if (!flag) { return(null); } return(new PgpSecretKeyRing(list, secRing.extraPubKeys)); }
/// <summary>Return the secret key ring which contains the key referred to by keyId</summary> /// <param name="keyId">The ID of the secret key</param> public PgpSecretKeyRing GetSecretKeyRing( long keyId) { long id = keyId; if (secretRings.Contains(id)) { return((PgpSecretKeyRing)secretRings[id]); } foreach (PgpSecretKeyRing secretRing in GetKeyRings()) { PgpSecretKey secret = secretRing.GetSecretKey(keyId); if (secret != null) { return(secretRing); } } return(null); }
internal FormPassphrase(PgpSecretKey masterKey, PgpSecretKey key) { TopMost = true; InitializeComponent(); var userIds = masterKey.UserIds.GetEnumerator(); userIds.MoveNext(); var userId = userIds.Current.ToString(); var strength = key.PublicKey.BitStrength.ToString(); var createDate = key.PublicKey.CreationTime.ToShortDateString(); var alg = key.PublicKey.Algorithm.ToString().Replace("Algorithm", ""); var fingerPrint = key.PublicKey.GetFingerprint(); var fingerPrintLength = fingerPrint.Length; var keyId = fingerPrint[fingerPrintLength - 4].ToString("X2") + fingerPrint[fingerPrintLength - 3].ToString("X2") + fingerPrint[fingerPrintLength - 2].ToString("X2") + fingerPrint[fingerPrintLength - 1].ToString("X2"); labelKeyInfo.Text = string.Format("\"{0}\"\n{1}-{2} key, ID {3}\n{4}", userId, strength, alg, keyId, createDate); }
/// <summary> /// Replace the public key set on the secret ring with the corresponding key off the public ring. /// </summary> /// <param name="secretRing">Secret ring to be changed.</param> /// <param name="publicRing">Public ring containing the new public key set.</param> public static PgpSecretKeyRing ReplacePublicKeys( PgpSecretKeyRing secretRing, PgpPublicKeyRing publicRing) { IList newList = Platform.CreateArrayList(secretRing.keys.Count); foreach (PgpSecretKey sk in secretRing.keys) { PgpPublicKey pk = null; try { pk = publicRing.GetPublicKey(sk.KeyId); } catch (PgpException e) { throw new InvalidOperationException(e.Message, e); } newList.Add(PgpSecretKey.ReplacePublicKey(sk, pk)); } return(new PgpSecretKeyRing(newList)); }
public static PgpSecretKeyRing ReplacePublicKeys(PgpSecretKeyRing secretRing, PgpPublicKeyRing publicRing) { global::System.Collections.IList list = Platform.CreateArrayList(((global::System.Collections.ICollection)secretRing.keys).get_Count()); global::System.Collections.IEnumerator enumerator = ((global::System.Collections.IEnumerable)secretRing.keys).GetEnumerator(); try { while (enumerator.MoveNext()) { PgpSecretKey pgpSecretKey = (PgpSecretKey)enumerator.get_Current(); PgpPublicKey publicKey = publicRing.GetPublicKey(pgpSecretKey.KeyId); list.Add((object)PgpSecretKey.ReplacePublicKey(pgpSecretKey, publicKey)); } } finally { global::System.IDisposable disposable = enumerator as global::System.IDisposable; if (disposable != null) { disposable.Dispose(); } } return(new PgpSecretKeyRing(list)); }
public static PgpSecretKeyRing InsertSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) global::System.Collections.IList list = Platform.CreateArrayList((global::System.Collections.ICollection)secRing.keys); bool flag = false; bool flag2 = false; for (int i = 0; i != ((global::System.Collections.ICollection)list).get_Count(); i++) { PgpSecretKey pgpSecretKey = (PgpSecretKey)list.get_Item(i); if (pgpSecretKey.KeyId == secKey.KeyId) { flag = true; list.set_Item(i, (object)secKey); } if (pgpSecretKey.IsMasterKey) { flag2 = true; } } if (!flag) { if (secKey.IsMasterKey) { if (flag2) { throw new ArgumentException("cannot add a master key to a ring that already has one"); } list.Insert(0, (object)secKey); } else { list.Add((object)secKey); } } return(new PgpSecretKeyRing(list, secRing.extraPubKeys)); }
public PgpSecretKey GetSecretKey(long keyId) { global::System.Collections.IEnumerator enumerator = ((global::System.Collections.IEnumerable)keys).GetEnumerator(); try { while (enumerator.MoveNext()) { PgpSecretKey pgpSecretKey = (PgpSecretKey)enumerator.get_Current(); if (keyId == pgpSecretKey.KeyId) { return(pgpSecretKey); } } } finally { global::System.IDisposable disposable = enumerator as global::System.IDisposable; if (disposable != null) { disposable.Dispose(); } } return(null); }
/// <summary> /// Return a copy of the passed in secret key, encrypted using a new password /// and the passed in algorithm. /// </summary> /// <param name="key">The PgpSecretKey to be copied.</param> /// <param name="oldPassPhrase">The current password for the key.</param> /// <param name="newPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKey CopyWithNewPassword( PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { if (key.IsPrivateKeyEmpty) { throw new PgpException("no private key in this SecretKey - public key present only."); } byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); int s2kUsage = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; byte[] keyData; PublicKeyPacket pubKeyPacket = key.secret.PublicKeyPacket; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { s2kUsage = SecretKeyPacket.UsageNone; if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum { keyData = new byte[rawKeyData.Length - 18]; Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); byte[] check = Checksum(false, keyData, keyData.Length - 2); keyData[keyData.Length - 2] = check[0]; keyData[keyData.Length - 1] = check[1]; } else { keyData = rawKeyData; } } else { try { if (pubKeyPacket.Version >= 4) { keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv); } else { // TODO v3 RSA key encryption throw Platform.CreateNotImplementedException("v3 RSA"); } } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception encrypting key", e); } } SecretKeyPacket secret; if (key.secret is SecretSubkeyPacket) { secret = new SecretSubkeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return(new PgpSecretKey(secret, key.pub)); }
public static PgpSecretKey CopyWithNewPasswordRaw(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return(DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, clearPassPhrase: false, newEncAlgorithm, rand)); }
static bool PgpSecretKeyMatches (PgpSecretKey key, MailboxAddress mailbox) { var secure = mailbox as SecureMailboxAddress; if (secure != null && !string.IsNullOrEmpty (secure.Fingerprint)) { if (secure.Fingerprint.Length > 16) { var fingerprint = HexEncode (key.PublicKey.GetFingerprint ()); return secure.Fingerprint.Equals (fingerprint, StringComparison.OrdinalIgnoreCase); } else { var id = ((int) key.KeyId).ToString ("X2"); return secure.Fingerprint.EndsWith (id, StringComparison.OrdinalIgnoreCase); } } foreach (string userId in key.UserIds) { MailboxAddress email; if (!MailboxAddress.TryParse (userId, out email)) continue; if (mailbox.Address.Equals (email.Address, StringComparison.OrdinalIgnoreCase)) return true; } return false; }
/// <summary> /// Return a copy of the passed in secret key, encrypted using a new password /// and the passed in algorithm. /// </summary> /// <param name="key">The PgpSecretKey to be copied.</param> /// <param name="oldPassPhrase">The current password for the key.</param> /// <param name="newPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKey CopyWithNewPassword( PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); int s2kUsage = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; byte[] keyData; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { s2kUsage = SecretKeyPacket.UsageNone; if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum { keyData = new byte[rawKeyData.Length - 18]; Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); byte[] check = Checksum(false, keyData, keyData.Length - 2); keyData[keyData.Length - 2] = check[0]; keyData[keyData.Length - 1] = check[1]; } else { keyData = rawKeyData; } } else { try { keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception encrypting key", e); } } SecretKeyPacket secret; if (key.secret is SecretSubkeyPacket) { secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return new PgpSecretKey(secret, key.pub); }
/// <summary> /// Build a PGP key pair /// </summary> /// <param name="bits">number of bits in key, e.g. 2048</param> /// <param name="identifier">key identifier, e.g. "Your Name <*****@*****.**>" </param> /// <param name="password">key password or null</param> /// <param name="privateKey">returned ascii private key</param> /// <param name="publicKey">returned ascii public key</param> public static void PGPGenerateKey(int bits, string identifier, string password, out string privateKey, out string publicKey) { // generate a new RSA keypair RsaKeyPairGenerator gen = new RsaKeyPairGenerator(); gen.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(0x101), new Org.BouncyCastle.Security.SecureRandom(), bits, 80)); AsymmetricCipherKeyPair pair = gen.GenerateKeyPair(); // create PGP subpacket PgpSignatureSubpacketGenerator hashedGen = new PgpSignatureSubpacketGenerator(); hashedGen.SetKeyFlags(true, PgpKeyFlags.CanCertify | PgpKeyFlags.CanSign | PgpKeyFlags.CanEncryptCommunications | PgpKeyFlags.CanEncryptStorage); hashedGen.SetPreferredCompressionAlgorithms(false, new int[] { (int)CompressionAlgorithmTag.Zip }); hashedGen.SetPreferredHashAlgorithms(false, new int[] { (int)HashAlgorithmTag.Sha1 }); hashedGen.SetPreferredSymmetricAlgorithms(false, new int[] { (int)SymmetricKeyAlgorithmTag.Cast5 }); PgpSignatureSubpacketVector sv = hashedGen.Generate(); PgpSignatureSubpacketGenerator unhashedGen = new PgpSignatureSubpacketGenerator(); // create the PGP key PgpSecretKey secretKey = new PgpSecretKey( PgpSignature.DefaultCertification, PublicKeyAlgorithmTag.RsaGeneral, pair.Public, pair.Private, DateTime.Now, identifier, SymmetricKeyAlgorithmTag.Cast5, (password != null ? password.ToCharArray() : null), hashedGen.Generate(), unhashedGen.Generate(), new Org.BouncyCastle.Security.SecureRandom()); // extract the keys using (MemoryStream ms = new MemoryStream()) { using (ArmoredOutputStream ars = new ArmoredOutputStream(ms)) { secretKey.Encode(ars); } privateKey = Encoding.ASCII.GetString(ms.ToArray()); } using (MemoryStream ms = new MemoryStream()) { using (ArmoredOutputStream ars = new ArmoredOutputStream(ms)) { secretKey.PublicKey.Encode(ars); } publicKey = Encoding.ASCII.GetString(ms.ToArray()); } }
internal static PgpSecretKey DoCopyWithNewPassword( PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, bool clearPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { if (key.IsPrivateKeyEmpty) throw new PgpException("no private key in this SecretKey - public key present only."); byte[] rawKeyData = key.ExtractKeyData(rawOldPassPhrase, clearPassPhrase); int s2kUsage = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; byte[] keyData; PublicKeyPacket pubKeyPacket = key.secret.PublicKeyPacket; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { s2kUsage = SecretKeyPacket.UsageNone; if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum { keyData = new byte[rawKeyData.Length - 18]; Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); byte[] check = Checksum(false, keyData, keyData.Length - 2); keyData[keyData.Length - 2] = check[0]; keyData[keyData.Length - 1] = check[1]; } else { keyData = rawKeyData; } } else { if (s2kUsage == SecretKeyPacket.UsageNone) { s2kUsage = SecretKeyPacket.UsageChecksum; } try { if (pubKeyPacket.Version >= 4) { keyData = EncryptKeyDataV4(rawKeyData, newEncAlgorithm, HashAlgorithmTag.Sha1, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv); } else { keyData = EncryptKeyDataV3(rawKeyData, newEncAlgorithm, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv); } } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception encrypting key", e); } } SecretKeyPacket secret; if (key.secret is SecretSubkeyPacket) { secret = new SecretSubkeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket(pubKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return new PgpSecretKey(secret, key.pub); }
/// <summary> /// Returns a new key ring with the secret key passed in either added or /// replacing an existing one with the same key ID. /// </summary> /// <param name="secRing">The secret key ring to be modified.</param> /// <param name="secKey">The secret key to be inserted.</param> /// <returns>A new <c>PgpSecretKeyRing</c></returns> public static PgpSecretKeyRing InsertSecretKey( PgpSecretKeyRing secRing, PgpSecretKey secKey) { IList keys = Platform.CreateArrayList(secRing.keys); bool found = false; bool masterFound = false; for (int i = 0; i != keys.Count; i++) { PgpSecretKey key = (PgpSecretKey) keys[i]; if (key.KeyId == secKey.KeyId) { found = true; keys[i] = secKey; } if (key.IsMasterKey) { masterFound = true; } } if (!found) { if (secKey.IsMasterKey) { if (masterFound) throw new ArgumentException("cannot add a master key to a ring that already has one"); keys.Insert(0, secKey); } else { keys.Add(secKey); } } return new PgpSecretKeyRing(keys, secRing.extraPubKeys); }
/// <summary> /// Gets the password for key. /// </summary> /// <remarks> /// Gets the password for key. /// </remarks> /// <returns>The password for key.</returns> /// <param name="key">The key.</param> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password request. /// </exception> protected abstract string GetPasswordForKey (PgpSecretKey key);
/// <summary> /// Gets the private key from the specified secret key. /// </summary> /// <remarks> /// Gets the private key from the specified secret key. /// </remarks> /// <returns>The private key.</returns> /// <param name="key">The secret key.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="key"/> is <c>null</c>. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> protected PgpPrivateKey GetPrivateKey (PgpSecretKey key) { int attempts = 0; string password; if (key == null) throw new ArgumentNullException ("key"); do { if ((password = GetPasswordForKey (key)) == null) throw new OperationCanceledException (); try { var privateKey = key.ExtractPrivateKey (password.ToCharArray ()); // Note: the private key will be null if the private key is empty. if (privateKey == null) break; return privateKey; } catch (Exception ex) { #if DEBUG Debug.WriteLine (string.Format ("Failed to extract secret key: {0}", ex)); #endif } attempts++; } while (attempts < 3); throw new UnauthorizedAccessException (); }
/// <summary> /// Creates a new <see cref="MultipartSigned"/>. /// </summary> /// <remarks> /// Cryptographically signs the entity using the supplied signer and digest algorithm in /// order to generate a detached signature and then adds the entity along with the /// detached signature data to a new multipart/signed part. /// </remarks> /// <returns>A new <see cref="MultipartSigned"/> instance.</returns> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="entity">The entity to sign.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="entity"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <paramref name="signer"/> cannot be used for signing. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// The <paramref name="digestAlgo"/> was out of range. /// </exception> /// <exception cref="System.NotSupportedException"> /// <para>A cryptography context suitable for signing could not be found.</para> /// <para>-or-</para> /// <para>The <paramref name="digestAlgo"/> is not supported.</para> /// </exception> /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException"> /// An error occurred in the OpenPGP subsystem. /// </exception> public static MultipartSigned Create (PgpSecretKey signer, DigestAlgorithm digestAlgo, MimeEntity entity) { using (var ctx = (OpenPgpContext) CryptographyContext.Create ("application/pgp-signature")) { return Create (ctx, signer, digestAlgo, entity); } }
public static PgpSecretKey CopyWithNewPasswordUtf8(PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return(DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, utf8: true), PgpUtilities.EncodePassPhrase(newPassPhrase, utf8: true), clearPassPhrase: true, newEncAlgorithm, rand)); }
public static MultipartEncrypted Create (OpenPgpContext ctx, PgpSecretKey signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable<PgpPublicKey> recipients, MimeEntity entity) { return SignAndEncrypt (ctx, signer, digestAlgo, cipherAlgo, recipients, entity); }
public static MultipartEncrypted Create (PgpSecretKey signer, DigestAlgorithm digestAlgo, IEnumerable<PgpPublicKey> recipients, MimeEntity entity) { return SignAndEncrypt (signer, digestAlgo, recipients, entity); }
protected override string GetPasswordForKey(PgpSecretKey key) { return "no.secret"; }
/// <summary> /// Return a copy of the passed in secret key, encrypted using a new password /// and the passed in algorithm. /// </summary> /// <remarks> /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes). /// </remarks> /// <param name="key">The PgpSecretKey to be copied.</param> /// <param name="oldPassPhrase">The current password for the key.</param> /// <param name="newPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKey CopyWithNewPasswordUtf8( PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, true), PgpUtilities.EncodePassPhrase(newPassPhrase, true), true, newEncAlgorithm, rand); }
/// <summary> /// Cryptographically signs the content. /// </summary> /// <remarks> /// Cryptographically signs the content using the specified signer and digest algorithm. /// </remarks> /// <returns>A new <see cref="MimeKit.MimePart"/> instance /// containing the detached signature data.</returns> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="content">The content.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="content"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <paramref name="signer"/> cannot be used for signing. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// The <paramref name="digestAlgo"/> was out of range. /// </exception> /// <exception cref="System.NotSupportedException"> /// The <paramref name="digestAlgo"/> is not supported. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public ApplicationPgpSignature Sign (PgpSecretKey signer, DigestAlgorithm digestAlgo, Stream content) { if (signer == null) throw new ArgumentNullException ("signer"); if (!signer.IsSigningKey) throw new ArgumentException ("The specified secret key cannot be used for signing.", "signer"); if (content == null) throw new ArgumentNullException ("content"); var hashAlgorithm = GetHashAlgorithm (digestAlgo); var memory = new MemoryBlockStream (); using (var armored = new ArmoredOutputStream (memory)) { var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); using (var compressed = compresser.Open (armored)) { var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); var buf = new byte[4096]; int nread; signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); while ((nread = content.Read (buf, 0, buf.Length)) > 0) signatureGenerator.Update (buf, 0, nread); var signature = signatureGenerator.Generate (); signature.Encode (compressed); compressed.Flush (); } armored.Flush (); } memory.Position = 0; return new ApplicationPgpSignature (memory); }
/// <summary> /// Return a copy of the passed in secret key, encrypted using a new password /// and the passed in algorithm. /// </summary> /// <remarks> /// Allows the caller to handle the encoding of the passphrase to bytes. /// </remarks> /// <param name="key">The PgpSecretKey to be copied.</param> /// <param name="rawOldPassPhrase">The current password for the key.</param> /// <param name="rawNewPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKey CopyWithNewPasswordRaw( PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { return DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, false, newEncAlgorithm, rand); }
static char[] PasswordCallback(PgpSecretKey masterKey, PgpSecretKey key) { return password; }
/// <summary>Replace the passed the public key on the passed in secret key.</summary> /// <param name="secretKey">Secret key to change.</param> /// <param name="publicKey">New public key.</param> /// <returns>A new secret key.</returns> /// <exception cref="ArgumentException">If KeyId's do not match.</exception> public static PgpSecretKey ReplacePublicKey( PgpSecretKey secretKey, PgpPublicKey publicKey) { if (publicKey.KeyId != secretKey.KeyId) throw new ArgumentException("KeyId's do not match"); return new PgpSecretKey(secretKey.secret, publicKey); }
/// <summary> /// Gets the private key from the specified secret key. /// </summary> /// <returns>The private key.</returns> /// <param name="key">The secret key.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="key"/> is <c>null</c>. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> protected PgpPrivateKey GetPrivateKey(PgpSecretKey key) { int attempts = 0; string password; if (key == null) throw new ArgumentNullException ("key"); do { if ((password = GetPasswordForKey (key)) == null) throw new OperationCanceledException (); try { return key.ExtractPrivateKey (password.ToCharArray ()); } catch (Exception ex) { Debug.WriteLine ("Failed to extract secret key: {0}", ex); } attempts++; } while (attempts < 3); throw new UnauthorizedAccessException (); }
/// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary> /// <param name="secRing">The secret key ring to be modified.</param> /// <param name="secKey">The secret key to be removed.</param> /// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns> public static PgpSecretKeyRing RemoveSecretKey( PgpSecretKeyRing secRing, PgpSecretKey secKey) { IList keys = Platform.CreateArrayList(secRing.keys); bool found = false; for (int i = 0; i < keys.Count; i++) { PgpSecretKey key = (PgpSecretKey)keys[i]; if (key.KeyId == secKey.KeyId) { found = true; keys.RemoveAt(i); } } return found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null; }
/// <summary> /// Creates a new <see cref="MultipartEncrypted"/>. /// </summary> /// <remarks> /// Signs the entity using the supplied signer and digest algorithm and then encrypts to /// the specified recipients, encapsulating the result in a new multipart/encrypted part. /// </remarks> /// <returns>A new <see cref="MimeKit.Cryptography.MultipartEncrypted"/> instance containing /// the signed and encrypted version of the specified entity.</returns> /// <param name="ctx">The OpenPGP cryptography context to use for singing and encrypting.</param> /// <param name="signer">The signer to use to sign the entity.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="recipients">The recipients for the encrypted entity.</param> /// <param name="entity">The entity to sign and encrypt.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="ctx"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="recipients"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="entity"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="signer"/> cannot be used for signing.</para> /// <para>-or-</para> /// <para>One or more of the recipient keys cannot be used for encrypting.</para> /// <para>-or-</para> /// <para>No recipients were specified.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// The <paramref name="digestAlgo"/> was out of range. /// </exception> /// <exception cref="System.NotSupportedException"> /// The <paramref name="digestAlgo"/> is not supported. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public static MultipartEncrypted Create (OpenPgpContext ctx, PgpSecretKey signer, DigestAlgorithm digestAlgo, IEnumerable<PgpPublicKey> recipients, MimeEntity entity) { if (ctx == null) throw new ArgumentNullException ("ctx"); if (signer == null) throw new ArgumentNullException ("signer"); if (recipients == null) throw new ArgumentNullException ("recipients"); if (entity == null) throw new ArgumentNullException ("entity"); using (var memory = new MemoryStream ()) { var options = FormatOptions.Default.Clone (); options.NewLineFormat = NewLineFormat.Dos; PrepareEntityForEncrypting (entity); entity.WriteTo (options, memory); memory.Position = 0; var encrypted = new MultipartEncrypted (); encrypted.ContentType.Parameters["protocol"] = ctx.EncryptionProtocol; // add the protocol version part encrypted.Add (new ApplicationPgpEncrypted ()); // add the encrypted entity as the second part encrypted.Add (ctx.SignAndEncrypt (signer, digestAlgo, recipients, memory)); return encrypted; } }
/// <summary> /// Return a copy of the passed in secret key, encrypted using a new password /// and the passed in algorithm. /// </summary> /// <param name="key">The PgpSecretKey to be copied.</param> /// <param name="oldPassPhrase">The current password for the key.</param> /// <param name="newPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKey CopyWithNewPassword( PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); int s2kUsage = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; byte[] keyData = null; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { s2kUsage = SecretKeyPacket.UsageNone; if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum { keyData = new byte[rawKeyData.Length - 18]; Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); byte[] check = Checksum(false, keyData, keyData.Length - 2); keyData[keyData.Length - 2] = check[0]; keyData[keyData.Length - 1] = check[1]; } else { keyData = rawKeyData; } } else { IBufferedCipher c; try { string cName = PgpUtilities.GetSymmetricCipherName(newEncAlgorithm); c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding"); } catch (Exception e) { throw new PgpException("Exception creating cipher", e); } iv = new byte[8]; rand.NextBytes(iv); s2k = new S2k(HashAlgorithmTag.Sha1, iv, 0x60); try { KeyParameter sKey = PgpUtilities.MakeKeyFromPassPhrase(newEncAlgorithm, s2k, newPassPhrase); iv = new byte[c.GetBlockSize()]; rand.NextBytes(iv); c.Init(true, new ParametersWithIV(sKey, iv)); keyData = c.DoFinal(rawKeyData); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception encrypting key", e); } } SecretKeyPacket secret; if (key.secret is SecretSubkeyPacket) { secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } if (key.subSigs == null) { return(new PgpSecretKey(secret, key.trust, key.keySigs, key.ids, key.idTrusts, key.idSigs, key.pub)); } return(new PgpSecretKey(secret, key.trust, key.subSigs, key.pub)); }
/// <summary> /// Creates a new <see cref="MultipartEncrypted"/>. /// </summary> /// <remarks> /// Signs the entity using the supplied signer and digest algorithm and then encrypts to /// the specified recipients, encapsulating the result in a new multipart/encrypted part. /// </remarks> /// <returns>A new <see cref="MimeKit.Cryptography.MultipartEncrypted"/> instance containing /// the signed and encrypted version of the specified entity.</returns> /// <param name="signer">The signer to use to sign the entity.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="recipients">The recipients for the encrypted entity.</param> /// <param name="entity">The entity to sign and encrypt.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="recipients"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="entity"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="signer"/> cannot be used for signing.</para> /// <para>-or-</para> /// <para>One or more of the recipient keys cannot be used for encrypting.</para> /// <para>-or-</para> /// <para>No recipients were specified.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// The <paramref name="digestAlgo"/> was out of range. /// </exception> /// <exception cref="System.NotSupportedException"> /// <para>A default <see cref="OpenPgpContext"/> has not been registered.</para> /// <para>-or-</para> /// <para>The <paramref name="digestAlgo"/> is not supported.</para> /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public static MultipartEncrypted Create (PgpSecretKey signer, DigestAlgorithm digestAlgo, IEnumerable<PgpPublicKey> recipients, MimeEntity entity) { if (signer == null) throw new ArgumentNullException ("signer"); if (recipients == null) throw new ArgumentNullException ("recipients"); if (entity == null) throw new ArgumentNullException ("entity"); using (var ctx = (OpenPgpContext) CryptographyContext.Create ("application/pgp-encrypted")) { return Create (ctx, signer, digestAlgo, recipients, entity); } }
static bool PgpSecretKeyMatches(PgpSecretKey key, MailboxAddress mailbox) { foreach (string userId in key.UserIds) { MailboxAddress email; if (!MailboxAddress.TryParse (userId, out email)) continue; if (string.Compare (mailbox.Address, email.Address, StringComparison.OrdinalIgnoreCase) == 0) return true; } return false; }
/// <summary>Returns a new key ring with the secret key passed in removed from the key ring.</summary> /// <param name="secRing">The secret key ring to be modified.</param> /// <param name="secKey">The secret key to be removed.</param> /// <returns>A new <c>PgpSecretKeyRing</c>, or null if secKey is not found.</returns> public static PgpSecretKeyRing RemoveSecretKey(PgpSecretKeyRing secRing, PgpSecretKey secKey) { var keys = Platform.CreateArrayList(secRing._keys); var found = false; for (var i = 0; i < keys.Count; i++) { var key = keys[i]; if (key.KeyId != secKey.KeyId) continue; found = true; keys.RemoveAt(i); } return found ? new PgpSecretKeyRing(keys, secRing._extraPubKeys) : null; }
/// <summary> /// Cryptographically signs and encrypts the specified content for the specified recipients. /// </summary> /// <remarks> /// Cryptographically signs and encrypts the specified content for the specified recipients. /// </remarks> /// <returns>A new <see cref="MimeKit.MimePart"/> instance /// containing the encrypted data.</returns> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="cipherAlgo">The encryption algorithm.</param> /// <param name="recipients">The recipients.</param> /// <param name="content">The content.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="recipients"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="content"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="signer"/> cannot be used for signing.</para> /// <para>-or-</para> /// <para>One or more of the recipient keys cannot be used for encrypting.</para> /// <para>-or-</para> /// <para>No recipients were specified.</para> /// </exception> /// <exception cref="System.NotSupportedException"> /// The specified encryption algorithm is not supported. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable<PgpPublicKey> recipients, Stream content) { // TODO: document the exceptions that can be thrown by BouncyCastle if (signer == null) throw new ArgumentNullException ("signer"); if (!signer.IsSigningKey) throw new ArgumentException ("The specified secret key cannot be used for signing.", "signer"); if (recipients == null) throw new ArgumentNullException ("recipients"); if (content == null) throw new ArgumentNullException ("content"); var encrypter = new PgpEncryptedDataGenerator (GetSymmetricKeyAlgorithm (cipherAlgo), true); var hashAlgorithm = GetHashAlgorithm (digestAlgo); int count = 0; foreach (var recipient in recipients) { if (!recipient.IsEncryptionKey) throw new ArgumentException ("One or more of the recipient keys cannot be used for encrypting.", "recipients"); encrypter.AddMethod (recipient); count++; } if (count == 0) throw new ArgumentException ("No recipients specified.", "recipients"); var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); using (var compressed = new MemoryBlockStream ()) { using (var signed = compresser.Open (compressed)) { var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); var subpacket = new PgpSignatureSubpacketGenerator (); foreach (string userId in signer.PublicKey.GetUserIds ()) { subpacket.SetSignerUserId (false, userId); break; } signatureGenerator.SetHashedSubpackets (subpacket.Generate ()); var onepass = signatureGenerator.GenerateOnePassVersion (false); onepass.Encode (signed); var literalGenerator = new PgpLiteralDataGenerator (); using (var literal = literalGenerator.Open (signed, 't', "mime.txt", content.Length, DateTime.Now)) { var buf = new byte[4096]; int nread; while ((nread = content.Read (buf, 0, buf.Length)) > 0) { signatureGenerator.Update (buf, 0, nread); literal.Write (buf, 0, nread); } literal.Flush (); } var signature = signatureGenerator.Generate (); signature.Encode (signed); signed.Flush (); } compressed.Position = 0; var memory = new MemoryBlockStream (); using (var armored = new ArmoredOutputStream (memory)) { using (var encrypted = encrypter.Open (armored, compressed.Length)) { compressed.CopyTo (encrypted, 4096); encrypted.Flush (); } armored.Flush (); } memory.Position = 0; return new MimePart ("application", "octet-stream") { ContentDisposition = new ContentDisposition ("attachment"), ContentObject = new ContentObject (memory) }; } }
/// <summary> /// Return a copy of the passed in secret key, encrypted using a new password /// and the passed in algorithm. /// </summary> /// <param name="key">The PgpSecretKey to be copied.</param> /// <param name="oldPassPhrase">The current password for the key.</param> /// <param name="newPassPhrase">The new password for the key.</param> /// <param name="newEncAlgorithm">The algorithm to be used for the encryption.</param> /// <param name="rand">Source of randomness.</param> public static PgpSecretKey CopyWithNewPassword( PgpSecretKey key, char[] oldPassPhrase, char[] newPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand) { byte[] rawKeyData = key.ExtractKeyData(oldPassPhrase); int s2kUsage = key.secret.S2kUsage; byte[] iv = null; S2k s2k = null; byte[] keyData; if (newEncAlgorithm == SymmetricKeyAlgorithmTag.Null) { s2kUsage = SecretKeyPacket.UsageNone; if (key.secret.S2kUsage == SecretKeyPacket.UsageSha1) // SHA-1 hash, need to rewrite Checksum { keyData = new byte[rawKeyData.Length - 18]; Array.Copy(rawKeyData, 0, keyData, 0, keyData.Length - 2); byte[] check = Checksum(false, keyData, keyData.Length - 2); keyData[keyData.Length - 2] = check[0]; keyData[keyData.Length - 1] = check[1]; } else { keyData = rawKeyData; } } else { try { keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv); } catch (PgpException e) { throw e; } catch (Exception e) { throw new PgpException("Exception encrypting key", e); } } SecretKeyPacket secret; if (key.secret is SecretSubkeyPacket) { secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } else { secret = new SecretKeyPacket(key.secret.PublicKeyPacket, newEncAlgorithm, s2kUsage, s2k, iv, keyData); } return(new PgpSecretKey(secret, key.pub)); }
/// <summary> /// Creates a new <see cref="MultipartSigned"/>. /// </summary> /// <remarks> /// Cryptographically signs the entity using the supplied signer and digest algorithm in /// order to generate a detached signature and then adds the entity along with the /// detached signature data to a new multipart/signed part. /// </remarks> /// <returns>A new <see cref="MultipartSigned"/> instance.</returns> /// <param name="ctx">The OpenPGP context to use for signing.</param> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="entity">The entity to sign.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="ctx"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="entity"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <paramref name="signer"/> cannot be used for signing. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// The <paramref name="digestAlgo"/> was out of range. /// </exception> /// <exception cref="System.NotSupportedException"> /// The <paramref name="digestAlgo"/> is not supported. /// </exception> /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException"> /// An error occurred in the OpenPGP subsystem. /// </exception> public static MultipartSigned Create (OpenPgpContext ctx, PgpSecretKey signer, DigestAlgorithm digestAlgo, MimeEntity entity) { if (ctx == null) throw new ArgumentNullException ("ctx"); if (signer == null) throw new ArgumentNullException ("signer"); if (entity == null) throw new ArgumentNullException ("entity"); PrepareEntityForSigning (entity); using (var memory = new MemoryBlockStream ()) { using (var filtered = new FilteredStream (memory)) { // Note: see rfc3156, section 3 - second note filtered.Add (new ArmoredFromFilter ()); // Note: see rfc3156, section 5.4 (this is the main difference between rfc2015 and rfc3156) filtered.Add (new TrailingWhitespaceFilter ()); // Note: see rfc2015 or rfc3156, section 5.1 filtered.Add (new Unix2DosFilter ()); entity.WriteTo (filtered); filtered.Flush (); } memory.Position = 0; // Note: we need to parse the modified entity structure to preserve any modifications var parser = new MimeParser (memory, MimeFormat.Entity); var parsed = parser.ParseEntity (); memory.Position = 0; // sign the cleartext content var micalg = ctx.GetDigestAlgorithmName (digestAlgo); var signature = ctx.Sign (signer, digestAlgo, memory); var signed = new MultipartSigned (); // set the protocol and micalg Content-Type parameters signed.ContentType.Parameters["protocol"] = ctx.SignatureProtocol; signed.ContentType.Parameters["micalg"] = micalg; // add the modified/parsed entity as our first part signed.Add (parsed); // add the detached signature as the second part signed.Add (signature); return signed; } }
/// <summary> /// Cryptographically signs and encrypts the specified content for the specified recipients. /// </summary> /// <remarks> /// Cryptographically signs and encrypts the specified content for the specified recipients. /// </remarks> /// <returns>A new <see cref="MimeKit.MimePart"/> instance /// containing the encrypted data.</returns> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="recipients">The recipients.</param> /// <param name="content">The content.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="recipients"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="content"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="signer"/> cannot be used for signing.</para> /// <para>-or-</para> /// <para>One or more of the recipient keys cannot be used for encrypting.</para> /// <para>-or-</para> /// <para>No recipients were specified.</para> /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, IEnumerable<PgpPublicKey> recipients, Stream content) { return SignAndEncrypt (signer, digestAlgo, defaultAlgorithm, recipients, content); }
public char[] GetPasswordCallback(PgpSecretKey masterKey, PgpSecretKey key) { return "test".ToCharArray(); }
static bool PgpSecretKeyMatches (PgpSecretKey key, MailboxAddress mailbox) { var secure = mailbox as SecureMailboxAddress; if (secure != null) { var fingerprint = GetFingerprint (key.KeyId, secure.Fingerprint.Length); return secure.Fingerprint.EndsWith (fingerprint, StringComparison.OrdinalIgnoreCase); } foreach (string userId in key.UserIds) { MailboxAddress email; if (!MailboxAddress.TryParse (userId, out email)) continue; if (string.Compare (mailbox.Address, email.Address, StringComparison.OrdinalIgnoreCase) == 0) return true; } return false; }