General class to handle a PGP secret key object.
Example #1
0
        /// <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));
        }
Example #4
0
        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);
        }
Example #6
0
        /// <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));
        }
Example #7
0
        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);
        }
Example #10
0
 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();
         }
     }
 }
Example #11
0
        /// <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));
        }
Example #12
0
        /// <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);
        }
Example #13
0
        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);
		}
Example #16
0
        /// <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));
        }
Example #17
0
 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));
 }
Example #18
0
        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));
        }
Example #19
0
 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));
        }
Example #21
0
 public static PgpSecretKey CopyWithNewPasswordRaw(PgpSecretKey key, byte[] rawOldPassPhrase, byte[] rawNewPassPhrase, SymmetricKeyAlgorithmTag newEncAlgorithm, SecureRandom rand)
 {
     return(DoCopyWithNewPassword(key, rawOldPassPhrase, rawNewPassPhrase, clearPassPhrase: false, newEncAlgorithm, rand));
 }
Example #22
0
		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;
		}
Example #23
0
		/// <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);
        }
Example #24
0
		/// <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());
      }
    }
Example #25
0
        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 ();
		}
Example #29
0
		/// <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);
			}
		}
Example #30
0
 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);
		}
Example #33
0
 protected override string GetPasswordForKey(PgpSecretKey key)
 {
     return "no.secret";
 }
Example #34
0
 /// <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);
		}
Example #36
0
 /// <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);
 }
Example #37
0
		static char[] PasswordCallback(PgpSecretKey masterKey, PgpSecretKey key)
		{
			return password;
		}
Example #38
0
        /// <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);
        }
Example #39
0
        /// <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;
        }
Example #41
0
		/// <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;
			}
		}
Example #42
0
        /// <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));
        }
Example #43
0
		/// <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);
			}
		}
Example #44
0
        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)
				};
			}
		}
Example #47
0
        /// <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));
        }
Example #48
0
		/// <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);
		}
Example #50
0
		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;
		}