summary refs log tree commit diff
path: root/crypto
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-10-17 23:21:07 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-10-17 23:21:07 +0700
commita8866af2bf98dd3be651ae853ddf463a313e972a (patch)
treec013866e5a76a6dab34d0f505cc7bbfe63498dc7 /crypto
parentFix various warnings from recent commits (diff)
downloadBouncyCastle.NET-ed25519-a8866af2bf98dd3be651ae853ddf463a313e972a.tar.xz
https://github.com/bcgit/bc-csharp/issues/37
- Add alternative PGP methods involving passphrases to support UTF8 or caller-defined encodings
Diffstat (limited to 'crypto')
-rw-r--r--crypto/src/openpgp/PgpEncryptedDataGenerator.cs49
-rw-r--r--crypto/src/openpgp/PgpKeyRingGenerator.cs158
-rw-r--r--crypto/src/openpgp/PgpPbeEncryptedData.cs37
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs346
-rw-r--r--crypto/src/openpgp/PgpUtilities.cs50
-rw-r--r--crypto/test/src/openpgp/examples/ByteArrayHandler.cs2
-rw-r--r--crypto/test/src/openpgp/examples/PbeFileProcessor.cs2
-rw-r--r--crypto/test/src/openpgp/test/PGPPBETest.cs10
-rw-r--r--crypto/test/src/openpgp/test/PGPRSATest.cs2
-rw-r--r--crypto/test/src/openpgp/test/PgpKeyRingTest.cs6
-rw-r--r--crypto/test/src/openpgp/test/PgpUnicodeTest.cs15
11 files changed, 588 insertions, 89 deletions
diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
index 2a2e63961..06868eab1 100644
--- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -271,26 +271,55 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// <summary>
 		/// Add a PBE encryption method to the encrypted object using the default algorithm (S2K_SHA1).
 		/// </summary>
-		public void AddMethod(
-			char[] passPhrase) 
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        [Obsolete("Use version that takes an explicit s2kDigest parameter")]
+        public void AddMethod(char[] passPhrase)
 		{
 			AddMethod(passPhrase, HashAlgorithmTag.Sha1);
 		}
 
-		/// <summary>Add a PBE encryption method to the encrypted object.</summary>
-        public void AddMethod(
- 			char[]				passPhrase,
-			HashAlgorithmTag	s2kDigest)
+        /// <summary>Add a PBE encryption method to the encrypted object.</summary>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        public void AddMethod(char[] passPhrase, HashAlgorithmTag s2kDigest)
+        {
+            DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, false), true, s2kDigest);
+        }
+
+        /// <summary>Add a PBE encryption method to the encrypted object.</summary>
+        /// <remarks>
+        /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+        /// </remarks>
+        public void AddMethodUtf8(char[] passPhrase, HashAlgorithmTag s2kDigest)
+        {
+            DoAddMethod(PgpUtilities.EncodePassPhrase(passPhrase, true), true, s2kDigest);
+        }
+
+        /// <summary>Add a PBE encryption method to the encrypted object.</summary>
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public void AddMethodRaw(byte[] rawPassPhrase, HashAlgorithmTag s2kDigest)
+        {
+            DoAddMethod(rawPassPhrase, false, s2kDigest);
+        }
+
+        internal void DoAddMethod(byte[] rawPassPhrase, bool clearPassPhrase, HashAlgorithmTag s2kDigest)
         {
             byte[] iv = new byte[8];
-			rand.NextBytes(iv);
+            rand.NextBytes(iv);
 
-			S2k s2k = new S2k(s2kDigest, iv, 0x60);
+            S2k s2k = new S2k(s2kDigest, iv, 0x60);
 
-			methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.MakeKeyFromPassPhrase(defAlgorithm, s2k, passPhrase)));
+            methods.Add(new PbeMethod(defAlgorithm, s2k, PgpUtilities.DoMakeKeyFromPassPhrase(defAlgorithm, s2k, rawPassPhrase, clearPassPhrase)));
         }
 
-		/// <summary>Add a public key encrypted session key to the encrypted object.</summary>
+        /// <summary>Add a public key encrypted session key to the encrypted object.</summary>
         public void AddMethod(
             PgpPublicKey key)
         {
diff --git a/crypto/src/openpgp/PgpKeyRingGenerator.cs b/crypto/src/openpgp/PgpKeyRingGenerator.cs
index efeea9d5b..4f6a4b12f 100644
--- a/crypto/src/openpgp/PgpKeyRingGenerator.cs
+++ b/crypto/src/openpgp/PgpKeyRingGenerator.cs
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         private SymmetricKeyAlgorithmTag	encAlgorithm;
         private HashAlgorithmTag            hashAlgorithm;
         private int                         certificationLevel;
-        private char[]                      passPhrase;
+        private byte[]                      rawPassPhrase;
 		private bool						useSha1;
 		private PgpKeyPair                  masterKey;
         private PgpSignatureSubpacketVector hashedPacketVector;
@@ -28,7 +28,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// Create a new key ring generator using old style checksumming. It is recommended to use
 		/// SHA1 checksumming where possible.
 		/// </summary>
-		/// <param name="certificationLevel">The certification level for keys on this ring.</param>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        /// <param name="certificationLevel">The certification level for keys on this ring.</param>
 		/// <param name="masterKey">The master key pair.</param>
 		/// <param name="id">The id to be associated with the ring.</param>
 		/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
@@ -36,6 +40,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
 		/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
 		/// <param name="rand">input secured random.</param>
+        [Obsolete("Use version taking an explicit 'useSha1' parameter instead")]
 		public PgpKeyRingGenerator(
 			int							certificationLevel,
 			PgpKeyPair					masterKey,
@@ -52,7 +57,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		/// <summary>
 		/// Create a new key ring generator.
 		/// </summary>
-		/// <param name="certificationLevel">The certification level for keys on this ring.</param>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        /// <param name="certificationLevel">The certification level for keys on this ring.</param>
 		/// <param name="masterKey">The master key pair.</param>
 		/// <param name="id">The id to be associated with the ring.</param>
 		/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
@@ -71,23 +80,86 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			PgpSignatureSubpacketVector	hashedPackets,
             PgpSignatureSubpacketVector	unhashedPackets,
             SecureRandom				rand)
+            : this(certificationLevel, masterKey, id, encAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+		/// <summary>
+		/// Create a new key ring generator.
+		/// </summary>
+		/// <param name="certificationLevel">The certification level for keys on this ring.</param>
+		/// <param name="masterKey">The master key pair.</param>
+		/// <param name="id">The id to be associated with the ring.</param>
+		/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+        /// <param name="utf8PassPhrase">
+        /// If true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+        /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+        /// </param>
+        /// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
+		/// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
+		/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+		/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+		/// <param name="rand">input secured random.</param>
+        public PgpKeyRingGenerator(
+            int							certificationLevel,
+            PgpKeyPair					masterKey,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            bool                        utf8PassPhrase,
+            char[]						passPhrase,
+			bool						useSha1,
+			PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(certificationLevel, masterKey, id, encAlgorithm,
+                PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase),
+                useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        /// <summary>
+		/// Create a new key ring generator.
+		/// </summary>
+		/// <param name="certificationLevel">The certification level for keys on this ring.</param>
+		/// <param name="masterKey">The master key pair.</param>
+		/// <param name="id">The id to be associated with the ring.</param>
+		/// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+		/// <param name="rawPassPhrase">The passPhrase to be used to protect secret keys.</param>
+		/// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
+		/// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+		/// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+		/// <param name="rand">input secured random.</param>
+        public PgpKeyRingGenerator(
+            int							certificationLevel,
+            PgpKeyPair					masterKey,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            byte[]						rawPassPhrase,
+			bool						useSha1,
+			PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
         {
             this.certificationLevel = certificationLevel;
             this.masterKey = masterKey;
             this.id = id;
             this.encAlgorithm = encAlgorithm;
-            this.passPhrase = passPhrase;
+            this.rawPassPhrase = rawPassPhrase;
 			this.useSha1 = useSha1;
 			this.hashedPacketVector = hashedPackets;
             this.unhashedPacketVector = unhashedPackets;
             this.rand = rand;
 
-			keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
+			keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand));
         }
 
         /// <summary>
         /// Create a new key ring generator.
         /// </summary>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
         /// <param name="certificationLevel">The certification level for keys on this ring.</param>
         /// <param name="masterKey">The master key pair.</param>
         /// <param name="id">The id to be associated with the ring.</param>
@@ -109,19 +181,85 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             PgpSignatureSubpacketVector hashedPackets,
             PgpSignatureSubpacketVector unhashedPackets,
             SecureRandom                rand)
+            : this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        /// <summary>
+        /// Create a new key ring generator.
+        /// </summary>
+        /// <param name="certificationLevel">The certification level for keys on this ring.</param>
+        /// <param name="masterKey">The master key pair.</param>
+        /// <param name="id">The id to be associated with the ring.</param>
+        /// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+        /// <param name="hashAlgorithm">The hash algorithm.</param>
+        /// <param name="utf8PassPhrase">
+        /// If true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+        /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+        /// </param>
+        /// <param name="passPhrase">The passPhrase to be used to protect secret keys.</param>
+        /// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
+        /// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+        /// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+        /// <param name="rand">input secured random.</param>
+        public PgpKeyRingGenerator(
+            int                         certificationLevel,
+            PgpKeyPair                  masterKey,
+            string                      id,
+            SymmetricKeyAlgorithmTag    encAlgorithm,
+            HashAlgorithmTag            hashAlgorithm,
+            bool                        utf8PassPhrase,
+            char[]                      passPhrase,
+            bool                        useSha1,
+            PgpSignatureSubpacketVector hashedPackets,
+            PgpSignatureSubpacketVector unhashedPackets,
+            SecureRandom                rand)
+            : this(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm,
+                PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase),
+                useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        /// <summary>
+        /// Create a new key ring generator.
+        /// </summary>
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        /// <param name="certificationLevel">The certification level for keys on this ring.</param>
+        /// <param name="masterKey">The master key pair.</param>
+        /// <param name="id">The id to be associated with the ring.</param>
+        /// <param name="encAlgorithm">The algorithm to be used to protect secret keys.</param>
+        /// <param name="hashAlgorithm">The hash algorithm.</param>
+        /// <param name="rawPassPhrase">The passPhrase to be used to protect secret keys.</param>
+        /// <param name="useSha1">Checksum the secret keys with SHA1 rather than the older 16 bit checksum.</param>
+        /// <param name="hashedPackets">Packets to be included in the certification hash.</param>
+        /// <param name="unhashedPackets">Packets to be attached unhashed to the certification.</param>
+        /// <param name="rand">input secured random.</param>
+        public PgpKeyRingGenerator(
+            int                         certificationLevel,
+            PgpKeyPair                  masterKey,
+            string                      id,
+            SymmetricKeyAlgorithmTag    encAlgorithm,
+            HashAlgorithmTag            hashAlgorithm,
+            byte[]                      rawPassPhrase,
+            bool                        useSha1,
+            PgpSignatureSubpacketVector hashedPackets,
+            PgpSignatureSubpacketVector unhashedPackets,
+            SecureRandom                rand)
         {
             this.certificationLevel = certificationLevel;
             this.masterKey = masterKey;
             this.id = id;
             this.encAlgorithm = encAlgorithm;
-            this.passPhrase = passPhrase;
+            this.rawPassPhrase = rawPassPhrase;
             this.useSha1 = useSha1;
             this.hashedPacketVector = hashedPackets;
             this.unhashedPacketVector = unhashedPackets;
             this.rand = rand;
             this.hashAlgorithm = hashAlgorithm;
 
-            keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, passPhrase, useSha1, hashedPackets, unhashedPackets, rand));
+            keys.Add(new PgpSecretKey(certificationLevel, masterKey, id, encAlgorithm, hashAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand));
         }
 
 		/// <summary>Add a subkey to the key ring to be generated with default certification.</summary>
@@ -172,7 +310,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 				subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
 
-				keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm, passPhrase, useSha1, rand));
+				keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
+                    rawPassPhrase, false, useSha1, rand, false));
 			}
             catch (PgpException e)
             {
@@ -215,7 +354,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 IList subSigs = Platform.CreateArrayList();
                 subSigs.Add(sGen.GenerateCertification(masterKey.PublicKey, keyPair.PublicKey));
 
-                keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm, passPhrase, useSha1, rand));
+                keys.Add(new PgpSecretKey(keyPair.PrivateKey, new PgpPublicKey(keyPair.PublicKey, null, subSigs), encAlgorithm,
+                    rawPassPhrase, false, useSha1, rand, false));
             }
             catch (PgpException)
             {
diff --git a/crypto/src/openpgp/PgpPbeEncryptedData.cs b/crypto/src/openpgp/PgpPbeEncryptedData.cs
index c5fe89407..f43f2f512 100644
--- a/crypto/src/openpgp/PgpPbeEncryptedData.cs
+++ b/crypto/src/openpgp/PgpPbeEncryptedData.cs
@@ -30,18 +30,43 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		}
 
 		/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
-        public Stream GetDataStream(
-            char[] passPhrase)
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        public Stream GetDataStream(char[] passPhrase)
+        {
+            return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, false), true);
+        }
+
+		/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
+        /// <remarks>
+        /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+        /// </remarks>
+        public Stream GetDataStreamUtf8(char[] passPhrase)
+        {
+            return DoGetDataStream(PgpUtilities.EncodePassPhrase(passPhrase, true), true);
+        }
+
+		/// <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public Stream GetDataStreamRaw(byte[] rawPassPhrase)
+        {
+            return DoGetDataStream(rawPassPhrase, false);
+        }
+
+        internal Stream DoGetDataStream(byte[] rawPassPhrase, bool clearPassPhrase)
         {
 			try
 			{
 				SymmetricKeyAlgorithmTag keyAlgorithm = keyData.EncAlgorithm;
 
-				KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(
-					keyAlgorithm, keyData.S2k, passPhrase);
-
+				KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(
+					keyAlgorithm, keyData.S2k, rawPassPhrase, clearPassPhrase);
 
-				byte[] secKeyData = keyData.GetSecKeyData();
+                byte[] secKeyData = keyData.GetSecKeyData();
 				if (secKeyData != null && secKeyData.Length > 0)
 				{
 					IBufferedCipher keyCipher = CipherUtilities.GetCipher(
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 1027393ce..0f472c1a4 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -30,18 +30,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             PgpPrivateKey				privKey,
             PgpPublicKey				pubKey,
             SymmetricKeyAlgorithmTag	encAlgorithm,
-            char[]						passPhrase,
-            bool						useSha1,
-            SecureRandom				rand)
-            : this(privKey, pubKey, encAlgorithm, passPhrase, useSha1, rand, false)
-        {
-        }
-
-        internal PgpSecretKey(
-            PgpPrivateKey				privKey,
-            PgpPublicKey				pubKey,
-            SymmetricKeyAlgorithmTag	encAlgorithm,
-            char[]						passPhrase,
+            byte[]						rawPassPhrase,
+            bool                        clearPassPhrase,
             bool						useSha1,
             SecureRandom				rand,
             bool						isMasterKey)
@@ -107,7 +97,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     byte[] encData;
                     if (pub.Version >= 4)
                     {
-                        encData = EncryptKeyData(keyData, encAlgorithm, passPhrase, rand, out s2k, out iv);
+                        encData = EncryptKeyData(keyData, encAlgorithm, rawPassPhrase, clearPassPhrase, rand, out s2k, out iv);
                     }
                     else
                     {
@@ -139,6 +129,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        [Obsolete("Use the constructor taking an explicit 'useSha1' parameter instead")]
         public PgpSecretKey(
             int							certificationLevel,
             PgpKeyPair					keyPair,
@@ -152,32 +147,151 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
         }
 
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        public PgpSecretKey(
+            int							certificationLevel,
+            PgpKeyPair					keyPair,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            bool						useSha1,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(certificationLevel, keyPair, id, encAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        /// <remarks>
+        /// If utf8PassPhrase is true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+        /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
         public PgpSecretKey(
             int							certificationLevel,
             PgpKeyPair					keyPair,
             string						id,
             SymmetricKeyAlgorithmTag	encAlgorithm,
+            bool                        utf8PassPhrase,
             char[]						passPhrase,
             bool						useSha1,
             PgpSignatureSubpacketVector	hashedPackets,
             PgpSignatureSubpacketVector	unhashedPackets,
             SecureRandom				rand)
-            : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets), encAlgorithm, passPhrase, useSha1, rand, true)
+            : this(certificationLevel, keyPair, id, encAlgorithm,
+                PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), true,
+                useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public PgpSecretKey(
+            int							certificationLevel,
+            PgpKeyPair					keyPair,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            byte[]						rawPassPhrase,
+            bool						useSha1,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(certificationLevel, keyPair, id, encAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        internal PgpSecretKey(
+            int							certificationLevel,
+            PgpKeyPair					keyPair,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            byte[]						rawPassPhrase,
+            bool                        clearPassPhrase,
+            bool						useSha1,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets),
+                encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, true)
+        {
+        }
+
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        public PgpSecretKey(
+            int                         certificationLevel,
+            PgpKeyPair                  keyPair,
+            string                      id,
+            SymmetricKeyAlgorithmTag    encAlgorithm,
+            HashAlgorithmTag            hashAlgorithm,
+            char[]                      passPhrase,
+            bool                        useSha1,
+            PgpSignatureSubpacketVector hashedPackets,
+            PgpSignatureSubpacketVector unhashedPackets,
+            SecureRandom                rand)
+            : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, false, passPhrase, useSha1, hashedPackets, unhashedPackets, rand)
         {
         }
 
+        /// <remarks>
+        /// If utf8PassPhrase is true, conversion of the passphrase to bytes uses Encoding.UTF8.GetBytes(), otherwise the conversion
+        /// is performed using Convert.ToByte(), which is the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
         public PgpSecretKey(
             int                         certificationLevel,
             PgpKeyPair                  keyPair,
             string                      id,
             SymmetricKeyAlgorithmTag    encAlgorithm,
             HashAlgorithmTag            hashAlgorithm,
+            bool                        utf8PassPhrase,
             char[]                      passPhrase,
             bool                        useSha1,
             PgpSignatureSubpacketVector hashedPackets,
             PgpSignatureSubpacketVector unhashedPackets,
             SecureRandom                rand)
-            : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm), encAlgorithm, passPhrase, useSha1, rand, true)
+            : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm,
+                PgpUtilities.EncodePassPhrase(passPhrase, utf8PassPhrase), true,
+                useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public PgpSecretKey(
+            int                         certificationLevel,
+            PgpKeyPair                  keyPair,
+            string                      id,
+            SymmetricKeyAlgorithmTag    encAlgorithm,
+            HashAlgorithmTag            hashAlgorithm,
+            byte[]                      rawPassPhrase,
+            bool                        useSha1,
+            PgpSignatureSubpacketVector hashedPackets,
+            PgpSignatureSubpacketVector unhashedPackets,
+            SecureRandom                rand)
+            : this(certificationLevel, keyPair, id, encAlgorithm, hashAlgorithm, rawPassPhrase, false, useSha1, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+        internal PgpSecretKey(
+            int                         certificationLevel,
+            PgpKeyPair                  keyPair,
+            string                      id,
+            SymmetricKeyAlgorithmTag    encAlgorithm,
+            HashAlgorithmTag            hashAlgorithm,
+            byte[]                      rawPassPhrase,
+            bool                        clearPassPhrase,
+            bool                        useSha1,
+            PgpSignatureSubpacketVector hashedPackets,
+            PgpSignatureSubpacketVector unhashedPackets,
+            SecureRandom                rand)
+            : this(keyPair.PrivateKey, CertifiedPublicKey(certificationLevel, keyPair, id, hashedPackets, unhashedPackets, hashAlgorithm),
+                encAlgorithm, rawPassPhrase, clearPassPhrase, useSha1, rand, true)
         {
         }
 
@@ -269,7 +383,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             SecureRandom				rand)
             : this(certificationLevel,
                 new PgpKeyPair(algorithm, pubKey, privKey, time),
-                id, encAlgorithm, passPhrase, hashedPackets, unhashedPackets, rand)
+                id, encAlgorithm, passPhrase, false, hashedPackets, unhashedPackets, rand)
         {
         }
 
@@ -367,8 +481,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             get { return pub.GetUserAttributes(); }
         }
 
-        private byte[] ExtractKeyData(
-            char[] passPhrase)
+        private byte[] ExtractKeyData(byte[] rawPassPhrase, bool clearPassPhrase)
         {
             SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm;
             byte[] encData = secret.GetSecretKeyData();
@@ -380,7 +493,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             // TODO Factor this block out as 'decryptData'
             try
             {
-                KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
+                KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, rawPassPhrase, clearPassPhrase);
                 byte[] iv = secret.GetIV();
                 byte[] data;
 
@@ -483,8 +596,34 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         }
 
         /// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
-        public PgpPrivateKey ExtractPrivateKey(
-            char[] passPhrase)
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        public PgpPrivateKey ExtractPrivateKey(char[] passPhrase)
+        {
+            return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, false), true);
+        }
+
+        /// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
+        /// <remarks>
+        /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+        /// </remarks>
+        public PgpPrivateKey ExtractPrivateKeyUtf8(char[] passPhrase)
+        {
+            return DoExtractPrivateKey(PgpUtilities.EncodePassPhrase(passPhrase, true), true);
+        }
+
+        /// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public PgpPrivateKey ExtractPrivateKeyRaw(byte[] rawPassPhrase)
+        {
+            return DoExtractPrivateKey(rawPassPhrase, false);
+        }
+
+        internal PgpPrivateKey DoExtractPrivateKey(byte[] rawPassPhrase, bool clearPassPhrase)
         {
             if (IsPrivateKeyEmpty)
                 return null;
@@ -492,7 +631,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             PublicKeyPacket pubPk = secret.PublicKeyPacket;
             try
             {
-                byte[] data = ExtractKeyData(passPhrase);
+                byte[] data = ExtractKeyData(rawPassPhrase, clearPassPhrase);
                 BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false));
                 AsymmetricKeyParameter privateKey;
                 switch (pubPk.Algorithm)
@@ -652,6 +791,10 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         /// Return a copy of the passed in secret key, encrypted using a new password
         /// and the passed in algorithm.
         /// </summary>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </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>
@@ -664,11 +807,67 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             SymmetricKeyAlgorithmTag	newEncAlgorithm,
             SecureRandom				rand)
         {
+            return DoCopyWithNewPassword(key, PgpUtilities.EncodePassPhrase(oldPassPhrase, false),
+                PgpUtilities.EncodePassPhrase(newPassPhrase, false), true, newEncAlgorithm, rand);
+        }
+
+        /// <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>
+        /// 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);
+        }
 
+        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(oldPassPhrase);
+            byte[]	rawKeyData = key.ExtractKeyData(rawOldPassPhrase, clearPassPhrase);
             int		s2kUsage = key.secret.S2kUsage;
             byte[]	iv = null;
             S2k		s2k = null;
@@ -696,11 +895,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
             else
             {
+                if (s2kUsage == SecretKeyPacket.UsageNone)
+                {
+                    s2kUsage = SecretKeyPacket.UsageChecksum;
+                }
+
                 try
                 {
                     if (pubKeyPacket.Version >= 4)
                     {
-                        keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+                        keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, rawNewPassPhrase, clearPassPhrase, rand, out s2k, out iv);
                     }
                     else
                     {
@@ -749,7 +953,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         private static byte[] EncryptKeyData(
             byte[]						rawKeyData,
             SymmetricKeyAlgorithmTag	encAlgorithm,
-            char[]						passPhrase,
+            byte[]						rawPassPhrase,
+            bool                        clearPassPhrase,
             SecureRandom				random,
             out S2k						s2k,
             out byte[]					iv)
@@ -769,7 +974,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             random.NextBytes(s2kIV);
             s2k = new S2k(HashAlgorithmTag.Sha1, s2kIV, 0x60);
 
-            KeyParameter kp = PgpUtilities.MakeKeyFromPassPhrase(encAlgorithm, s2k, passPhrase);
+            KeyParameter kp = PgpUtilities.DoMakeKeyFromPassPhrase(encAlgorithm, s2k, rawPassPhrase, clearPassPhrase);
 
             iv = new byte[c.GetBlockSize()];
             random.NextBytes(iv);
@@ -779,13 +984,42 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             return c.DoFinal(rawKeyData);
         }
 
-        /**
-         * Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
-         *
-         * @return a secret key object.
-         */
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+        /// </summary>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
         public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
         {
+            return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true, pubKey);
+        }
+
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+        /// </summary>
+        /// <remarks>
+        /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+        /// </remarks>
+        public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
+        {
+            return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true, pubKey);
+        }
+
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+        /// </summary>
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase, PgpPublicKey pubKey)
+        {
+            return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false, pubKey);
+        }
+
+        internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, PgpPublicKey pubKey)
+        {
             SXprUtilities.SkipOpenParenthesis(inputStream);
 
             string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
@@ -826,7 +1060,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
                 SXprUtilities.SkipCloseParenthesis(inputStream);
 
-                byte[] dValue = GetDValue(inputStream, passPhrase, curveName);
+                byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
                 // TODO: check SHA-1 hash.
 
                 return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null,
@@ -836,13 +1070,45 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             throw new PgpException("unknown key type found");
         }
 
-        /**
-        * Parse a secret key from one of the GPG S expression keys.
-        *
-        * @return a secret key object.
-        */
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys.
+        /// </summary>
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
         public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
         {
+            return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, false), true);
+        }
+
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys.
+        /// </summary>
+        /// <remarks>
+        /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+        /// </remarks>
+        public static PgpSecretKey ParseSecretKeyFromSExprUtf8(Stream inputStream, char[] passPhrase)
+        {
+            return DoParseSecretKeyFromSExpr(inputStream, PgpUtilities.EncodePassPhrase(passPhrase, true), true);
+        }
+
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys.
+        /// </summary>
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public static PgpSecretKey ParseSecretKeyFromSExprRaw(Stream inputStream, byte[] rawPassPhrase)
+        {
+            return DoParseSecretKeyFromSExpr(inputStream, rawPassPhrase, false);
+        }
+
+        /// <summary>
+        /// Parse a secret key from one of the GPG S expression keys.
+        /// </summary>
+        internal static PgpSecretKey DoParseSecretKeyFromSExpr(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase)
+        {
             SXprUtilities.SkipOpenParenthesis(inputStream);
 
             string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
@@ -891,7 +1157,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
                 SXprUtilities.SkipCloseParenthesis(inputStream);
 
-                byte[] dValue = GetDValue(inputStream, passPhrase, curveName);
+                byte[] dValue = GetDValue(inputStream, rawPassPhrase, clearPassPhrase, curveName);
                 // TODO: check SHA-1 hash.
 
                 return new PgpSecretKey(new SecretKeyPacket(pubPacket, SymmetricKeyAlgorithmTag.Null, null, null,
@@ -901,7 +1167,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             throw new PgpException("unknown key type found");
         }
 
-        private static byte[] GetDValue(Stream inputStream, char[] passPhrase, string curveName)
+        private static byte[] GetDValue(Stream inputStream, byte[] rawPassPhrase, bool clearPassPhrase, string curveName)
         {
             string type;
             SXprUtilities.SkipOpenParenthesis(inputStream);
@@ -932,7 +1198,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
 
             // TODO: recognise other algorithms
-            KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, passPhrase);
+            KeyParameter key = PgpUtilities.DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, rawPassPhrase, clearPassPhrase);
 
             byte[] data = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, secKeyData, 0, secKeyData.Length);
 
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index e4551db07..65c07b2e2 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -193,13 +193,44 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			return MakeKey(algorithm, keyBytes);
         }
 
-		public static KeyParameter MakeKeyFromPassPhrase(
-            SymmetricKeyAlgorithmTag	algorithm,
-            S2k							s2k,
-            char[]						passPhrase)
+        internal static byte[] EncodePassPhrase(char[] passPhrase, bool utf8)
+        {
+            return passPhrase == null
+                ? null
+                : utf8
+                ? Encoding.UTF8.GetBytes(passPhrase)
+                : Strings.ToByteArray(passPhrase);
+        }
+
+        /// <remarks>
+        /// Conversion of the passphrase characters to bytes is performed using Convert.ToByte(), which is
+        /// the historical behaviour of the library (1.7 and earlier).
+        /// </remarks>
+        public static KeyParameter MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
+        {
+            return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, false), true);
+        }
+
+        /// <remarks>
+        /// The passphrase is encoded to bytes using UTF8 (Encoding.UTF8.GetBytes).
+        /// </remarks>
+        public static KeyParameter MakeKeyFromPassPhraseUtf8(SymmetricKeyAlgorithmTag algorithm, S2k s2k, char[] passPhrase)
+        {
+            return DoMakeKeyFromPassPhrase(algorithm, s2k, EncodePassPhrase(passPhrase, true), true);
+        }
+
+        /// <remarks>
+        /// Allows the caller to handle the encoding of the passphrase to bytes.
+        /// </remarks>
+        public static KeyParameter MakeKeyFromPassPhraseRaw(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase)
+        {
+            return DoMakeKeyFromPassPhrase(algorithm, s2k, rawPassPhrase, false);
+        }
+
+        internal static KeyParameter DoMakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag algorithm, S2k s2k, byte[] rawPassPhrase, bool clearPassPhrase)
         {
 			int keySize = GetKeySize(algorithm);
-			byte[] pBytes = Encoding.UTF8.GetBytes(passPhrase);
+            byte[] pBytes = rawPassPhrase;
 			byte[] keyBytes = new byte[(keySize + 7) / 8];
 
 			int generatedBytes = 0;
@@ -308,12 +339,15 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 				loopCount++;
             }
 
-			Array.Clear(pBytes, 0, pBytes.Length);
+            if (clearPassPhrase && rawPassPhrase != null)
+            {
+                Array.Clear(rawPassPhrase, 0, rawPassPhrase.Length);
+            }
 
-			return MakeKey(algorithm, keyBytes);
+            return MakeKey(algorithm, keyBytes);
         }
 
-		/// <summary>Write out the passed in file as a literal data packet.</summary>
+        /// <summary>Write out the passed in file as a literal data packet.</summary>
         public static void WriteFileToLiteralData(
             Stream		output,
             char		fileType,
diff --git a/crypto/test/src/openpgp/examples/ByteArrayHandler.cs b/crypto/test/src/openpgp/examples/ByteArrayHandler.cs
index 676db8766..b5098ff66 100644
--- a/crypto/test/src/openpgp/examples/ByteArrayHandler.cs
+++ b/crypto/test/src/openpgp/examples/ByteArrayHandler.cs
@@ -123,7 +123,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
 			}
 
 			PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(algorithm, new SecureRandom());
-            encGen.AddMethod(passPhrase);
+            encGen.AddMethod(passPhrase, HashAlgorithmTag.Sha1);
 
 			Stream encOut = encGen.Open(output, compressedData.Length);
 
diff --git a/crypto/test/src/openpgp/examples/PbeFileProcessor.cs b/crypto/test/src/openpgp/examples/PbeFileProcessor.cs
index 66b1cc4ed..961704407 100644
--- a/crypto/test/src/openpgp/examples/PbeFileProcessor.cs
+++ b/crypto/test/src/openpgp/examples/PbeFileProcessor.cs
@@ -127,7 +127,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Examples
 
 				PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(
 					SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom());
-				encGen.AddMethod(passPhrase);
+                encGen.AddMethod(passPhrase, HashAlgorithmTag.Sha1);
 
 				Stream encOut = encGen.Open(outputStream, compressedData.Length);
 
diff --git a/crypto/test/src/openpgp/test/PGPPBETest.cs b/crypto/test/src/openpgp/test/PGPPBETest.cs
index 621cef684..29b786a83 100644
--- a/crypto/test/src/openpgp/test/PGPPBETest.cs
+++ b/crypto/test/src/openpgp/test/PGPPBETest.cs
@@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator(
 				SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
 
-            cPk.AddMethod(pass);
+            cPk.AddMethod(pass, HashAlgorithmTag.Sha1);
 
 			byte[] bOutData = bOut.ToArray();
 			Stream cOut = cPk.Open(new UncloseableStream(cbOut), bOutData.Length);
@@ -188,7 +188,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 			cPk = new PgpEncryptedDataGenerator(
 				SymmetricKeyAlgorithmTag.Cast5, new SecureRandom());
 
-			cPk.AddMethod(pass);
+            cPk.AddMethod(pass, HashAlgorithmTag.Sha1);
 
 			bOutData = bOut.ToArray();
 			cOut = cPk.Open(new UncloseableStream(cbOut), bOutData.Length);
@@ -233,7 +233,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             cPk = new PgpEncryptedDataGenerator(
 				SymmetricKeyAlgorithmTag.Cast5, rand);
 
-            cPk.AddMethod(pass);
+            cPk.AddMethod(pass, HashAlgorithmTag.Sha1);
 
 			cOut = cPk.Open(new UncloseableStream(cbOut), new byte[16]);
             {
@@ -256,7 +256,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             cPk = new PgpEncryptedDataGenerator(
 				SymmetricKeyAlgorithmTag.Cast5, true, rand);
 
-            cPk.AddMethod(pass);
+            cPk.AddMethod(pass, HashAlgorithmTag.Sha1);
 
             cOut = cPk.Open(new UncloseableStream(cbOut), new byte[16]);
             bOutData = bOut.ToArray();
@@ -328,7 +328,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 			cbOut = new MemoryStream();
 			cPk = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5, true, rand);
 
-			cPk.AddMethod(pass);
+            cPk.AddMethod(pass, HashAlgorithmTag.Sha1);
 
 			cOut = cPk.Open(new UncloseableStream(cbOut), new byte[16]);
 
diff --git a/crypto/test/src/openpgp/test/PGPRSATest.cs b/crypto/test/src/openpgp/test/PGPRSATest.cs
index 35f844483..82b569bbb 100644
--- a/crypto/test/src/openpgp/test/PGPRSATest.cs
+++ b/crypto/test/src/openpgp/test/PGPRSATest.cs
@@ -381,7 +381,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 
             encGen.AddMethod(pgpPubKey);
 
-            encGen.AddMethod("password".ToCharArray());
+            encGen.AddMethod("password".ToCharArray(), HashAlgorithmTag.Sha1);
 
             Stream cOut = encGen.Open(bcOut, bytes.Length);
 
diff --git a/crypto/test/src/openpgp/test/PgpKeyRingTest.cs b/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
index 9896c1ef6..43aef5afa 100644
--- a/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
+++ b/crypto/test/src/openpgp/test/PgpKeyRingTest.cs
@@ -1844,7 +1844,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             PgpKeyPair elgKeyPair = new PgpKeyPair(PublicKeyAlgorithmTag.ElGamalEncrypt, elgKp, DateTime.UtcNow);
 
             PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification, dsaKeyPair,
-                "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, new SecureRandom());
+                "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, false, null, null, new SecureRandom());
 
             keyRingGen.AddSubKey(elgKeyPair);
 
@@ -1904,12 +1904,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
             PgpKeyPair rsaKeyPair2 = new PgpKeyPair(PublicKeyAlgorithmTag.RsaGeneral, rsaKp, DateTime.UtcNow);
 
             PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification,
-                rsaKeyPair1, "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, random);
+                rsaKeyPair1, "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, false, null, null, random);
             PgpSecretKeyRing secRing1 = keyRingGen.GenerateSecretKeyRing();
             PgpPublicKeyRing pubRing1 = keyRingGen.GeneratePublicKeyRing();
 
             keyRingGen = new PgpKeyRingGenerator(PgpSignature.PositiveCertification,
-                rsaKeyPair2, "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, null, null, random);
+                rsaKeyPair2, "test", SymmetricKeyAlgorithmTag.Aes256, passPhrase, false, null, null, random);
             PgpSecretKeyRing secRing2 = keyRingGen.GenerateSecretKeyRing();
             PgpPublicKeyRing pubRing2 = keyRingGen.GeneratePublicKeyRing();
 
diff --git a/crypto/test/src/openpgp/test/PgpUnicodeTest.cs b/crypto/test/src/openpgp/test/PgpUnicodeTest.cs
index ce1df8980..534e8a471 100644
--- a/crypto/test/src/openpgp/test/PgpUnicodeTest.cs
+++ b/crypto/test/src/openpgp/test/PgpUnicodeTest.cs
@@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
     [TestFixture]
     public class PgpUnicodeTest
     {
-        private void DoTestKey(BigInteger keyId, string passphrase)
+        private void DoTestKey(BigInteger keyId, string passphrase, bool utf8)
         {
             PgpSecretKeyRingBundle secretKeyRing = LoadSecretKeyCollection("secring.gpg");
 
@@ -25,7 +25,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 
             try
             {
-                PgpPrivateKey privateKey = key.ExtractPrivateKey(passphrase.ToCharArray());
+                char[] pass = passphrase.ToCharArray();
+
+                PgpPrivateKey privateKey = utf8
+                    ?   key.ExtractPrivateKeyUtf8(pass)
+                    :   key.ExtractPrivateKey(pass);
 
                 Assert.IsTrue(privateKey.KeyId == keyId.LongValue);
             }
@@ -53,7 +57,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
  //             passwordFile.close();
  //             String passphrase = new String(password);            
 
-                DoTestKey(keyId, passphrase);
+                DoTestKey(keyId, passphrase, true);
 
                 // all fine!
 
@@ -75,7 +79,8 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
 
                 string passphrase = "Admin123";
 
-                DoTestKey(keyId, passphrase);
+                DoTestKey(keyId, passphrase, false);
+                DoTestKey(keyId, passphrase, true);
 
                 // all fine!
             }
@@ -102,7 +107,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp.Tests
                 string passphrase = reader.ReadLine();
                 passwordFile.Close();
 
-                DoTestKey(keyId, passphrase);
+                DoTestKey(keyId, passphrase, true);
 
                 // all fine!
             }