context: using System;
  using System.IO;
  using System.Text;
  
  using Org.BouncyCastle.Asn1;
  using Org.BouncyCastle.Crypto;
  using Org.BouncyCastle.Crypto.Parameters;
  using Org.BouncyCastle.Security;
  using Org.BouncyCastle.Utilities.Encoders;
  
  namespace Org.BouncyCastle.Bcpg.OpenPgp
  {
  	/// <remarks>Basic utility class.</remarks>
      public sealed class PgpUtilities
      {
          private PgpUtilities()
          {
          }
  
  		public static MPInteger[] DsaSigToMpi(
  			byte[] encoding)
  		{
  			DerInteger i1, i2;
  
  			try
  			{
  				Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
  
  				i1 = (DerInteger) s[0];
  				i2 = (DerInteger) s[1];
  			}
  			catch (IOException e)
  			{
  				throw new PgpException("exception encoding signature", e);
  			}
  
  			return new MPInteger[]{ new MPInteger(i1.Value), new MPInteger(i2.Value) };
  		}
  
  		public static string GetDigestName(
              HashAlgorithmTag hashAlgorithm)
          {
              switch (hashAlgorithm)
              {
  				case HashAlgorithmTag.Sha1:
  					return "SHA1";
  				case HashAlgorithmTag.MD2:
  					return "MD2";
  				case HashAlgorithmTag.MD5:
  					return "MD5";
  				case HashAlgorithmTag.RipeMD160:
  					return "RIPEMD160";
  				case HashAlgorithmTag.Sha224:
  					return "SHA224";
  				case HashAlgorithmTag.Sha256:
  					return "SHA256";
  				case HashAlgorithmTag.Sha384:
  					return "SHA384";
  				case HashAlgorithmTag.Sha512:
  					return "SHA512";
  				default:
  					throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
  			}
          }
  
  		public static string GetSignatureName(
              PublicKeyAlgorithmTag	keyAlgorithm,
              HashAlgorithmTag		hashAlgorithm)
          {
              string encAlg;
  			switch (keyAlgorithm)
              {
  				case PublicKeyAlgorithmTag.RsaGeneral:
  				case PublicKeyAlgorithmTag.RsaSign:
  					encAlg = "RSA";
  					break;
  				case PublicKeyAlgorithmTag.Dsa:
  					encAlg = "DSA";
  					break;
  				case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
  				case PublicKeyAlgorithmTag.ElGamalGeneral:
  					encAlg = "ElGamal";
  					break;
  				default:
  					throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
              }
  
  			return GetDigestName(hashAlgorithm) + "with" + encAlg;
          }
  
  		public static string GetSymmetricCipherName(
              SymmetricKeyAlgorithmTag algorithm)
          {
              switch (algorithm)
              {
  				case SymmetricKeyAlgorithmTag.Null:
  					return null;
  				case SymmetricKeyAlgorithmTag.TripleDes:
  					return "DESEDE";
  				case SymmetricKeyAlgorithmTag.Idea:
  					return "IDEA";
  				case SymmetricKeyAlgorithmTag.Cast5:
  					return "CAST5";
  				case SymmetricKeyAlgorithmTag.Blowfish:
  					return "Blowfish";
  				case SymmetricKeyAlgorithmTag.Safer:
  					return "SAFER";
  				case SymmetricKeyAlgorithmTag.Des:
  					return "DES";
  				case SymmetricKeyAlgorithmTag.Aes128:
  					return "AES";
  				case SymmetricKeyAlgorithmTag.Aes192:
  					return "AES";
  				case SymmetricKeyAlgorithmTag.Aes256:
  					return "AES";
  				case SymmetricKeyAlgorithmTag.Twofish:
  					return "Twofish";
  				default:
  					throw new PgpException("unknown symmetric algorithm: " + algorithm);
              }
          }
  
  		public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
          {
              int keySize;
              switch (algorithm)
              {
                  case SymmetricKeyAlgorithmTag.Des:
                      keySize = 64;
                      break;
                  case SymmetricKeyAlgorithmTag.Idea:
                  case SymmetricKeyAlgorithmTag.Cast5:
                  case SymmetricKeyAlgorithmTag.Blowfish:
                  case SymmetricKeyAlgorithmTag.Safer:
                  case SymmetricKeyAlgorithmTag.Aes128:
                      keySize = 128;
                      break;
                  case SymmetricKeyAlgorithmTag.TripleDes:
                  case SymmetricKeyAlgorithmTag.Aes192:
                      keySize = 192;
                      break;
                  case SymmetricKeyAlgorithmTag.Aes256:
                  case SymmetricKeyAlgorithmTag.Twofish:
                      keySize = 256;
                      break;
                  default:
                      throw new PgpException("unknown symmetric algorithm: " + algorithm);
              }
  
  			return keySize;
          }
  
  		public static KeyParameter MakeKey(
  			SymmetricKeyAlgorithmTag	algorithm,
  			byte[]						keyBytes)
  		{
  			string algName = GetSymmetricCipherName(algorithm);
  
  			return ParameterUtilities.CreateKeyParameter(algName, keyBytes);
  		}
  
  		public static KeyParameter MakeRandomKey(
              SymmetricKeyAlgorithmTag	algorithm,
              SecureRandom				random)
          {
              int keySize = GetKeySize(algorithm);
              byte[] keyBytes = new byte[(keySize + 7) / 8];
              random.NextBytes(keyBytes);
  			return MakeKey(algorithm, keyBytes);
          }
  
  		public static KeyParameter MakeKeyFromPassPhrase(
              SymmetricKeyAlgorithmTag	algorithm,
              S2k							s2k,
              char[]						passPhrase)
          {
  			int keySize = GetKeySize(algorithm);
  			byte[] pBytes = Encoding.ASCII.GetBytes(passPhrase);
  			byte[] keyBytes = new byte[(keySize + 7) / 8];
  
  			int generatedBytes = 0;
              int loopCount = 0;
  
  			while (generatedBytes < keyBytes.Length)
              {
  				IDigest digest;
  				if (s2k != null)
                  {
                      try
                      {
                          switch (s2k.HashAlgorithm)
                          {
  							case HashAlgorithmTag.Sha1:
  								digest = DigestUtilities.GetDigest("SHA1");
  								break;
  							default:
  								throw new PgpException("unknown hash algorithm: " + s2k.HashAlgorithm);
                          }
                      }
                      catch (Exception e)
                      {
                          throw new PgpException("can't find S2k digest", e);
                      }
  
  					for (int i = 0; i != loopCount; i++)
                      {
                          digest.Update(0);
                      }
  
  					byte[] iv = s2k.GetIV();
  
  					switch (s2k.Type)
                      {
  						case S2k.Simple:
  							digest.BlockUpdate(pBytes, 0, pBytes.Length);
  							break;
  						case S2k.Salted:
  							digest.BlockUpdate(iv, 0, iv.Length);
  							digest.BlockUpdate(pBytes, 0, pBytes.Length);
  							break;
  						case S2k.SaltedAndIterated:
  							long count = s2k.IterationCount;
  							digest.BlockUpdate(iv, 0, iv.Length);
  							digest.BlockUpdate(pBytes, 0, pBytes.Length);
  
  							count -= iv.Length + pBytes.Length;
  
  							while (count > 0)
  							{
  								if (count < iv.Length)
  								{
  									digest.BlockUpdate(iv, 0, (int)count);
  									break;
  								}
  								else
  								{
  									digest.BlockUpdate(iv, 0, iv.Length);
  									count -= iv.Length;
  								}
  
  								if (count < pBytes.Length)
  								{
  									digest.BlockUpdate(pBytes, 0, (int)count);
  									count = 0;
  								}
  								else
  								{
  									digest.BlockUpdate(pBytes, 0, pBytes.Length);
  									count -= pBytes.Length;
  								}
  							}
  							break;
  						default:
  							throw new PgpException("unknown S2k type: " + s2k.Type);
                      }
                  }
                  else
                  {
                      try
                      {
                          digest = DigestUtilities.GetDigest("MD5");
  
  						for (int i = 0; i != loopCount; i++)
                          {
                              digest.Update(0);
                          }
  
  						digest.BlockUpdate(pBytes, 0, pBytes.Length);
                      }
                      catch (Exception e)
                      {
                          throw new PgpException("can't find MD5 digest", e);
                      }
                  }
  
  				byte[] dig = DigestUtilities.DoFinal(digest);
  
  				if (dig.Length > (keyBytes.Length - generatedBytes))
                  {
                      Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
                  }
                  else
                  {
                      Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
                  }
  
  				generatedBytes += dig.Length;
  
  				loopCount++;
              }
  
  
gt: 			Array.Clear(pBytes, 0, pBytes.Length);