[英]Generating PGP key ring using Bouncy Castle (C#) results in key ID FFFFFFFF
I try to generate an RSA key pair using Bouncy Castle for C#. 我尝试使用Bouncy Castle for C#生成RSA密钥对。 I followed the tutorial for Java available at http://bouncycastle-pgp-cookbook.blogspot.de/2013_01_01_archive.html and create a master key and a signing key.
我遵循了Java教程, 网址为http://bouncycastle-pgp-cookbook.blogspot.de/2013_01_01_archive.html,并创建了一个主密钥和一个签名密钥。 My code looks like
我的代码看起来像
IAsymmetricCipherKeyPairGenerator generator
= GeneratorUtilities.GetKeyPairGenerator("RSA");
generator.Init(keyRingParams.RsaParams);
/* Create the master (signing-only) key. */
PgpKeyPair masterKeyPair = new PgpKeyPair(
PublicKeyAlgorithmTag.RsaSign,
generator.GenerateKeyPair(),
DateTime.UtcNow);
Debug.WriteLine("Generated master key with ID "
+ masterKeyPair.KeyId.ToString("X"));
PgpSignatureSubpacketGenerator masterSubpckGen
= new PgpSignatureSubpacketGenerator();
masterSubpckGen.SetKeyFlags(false, PgpKeyFlags.CanSign
| PgpKeyFlags.CanCertify);
masterSubpckGen.SetPreferredSymmetricAlgorithms(false,
(from a in keyRingParams.SymmetricAlgorithms
where a.IsSelected
select (int) a.Value).ToArray());
masterSubpckGen.SetPreferredHashAlgorithms(false,
(from a in keyRingParams.HashAlgorithms
where a.IsSelected
select (int) a.Value).ToArray());
/* Create a signing and encryption key for daily use. */
PgpKeyPair encKeyPair = new PgpKeyPair(
PublicKeyAlgorithmTag.RsaGeneral,
generator.GenerateKeyPair(),
DateTime.UtcNow);
Debug.WriteLine("Generated encryption key with ID "
+ encKeyPair.KeyId.ToString("X"));
PgpSignatureSubpacketGenerator encSubpckGen
= new PgpSignatureSubpacketGenerator();
encSubpckGen.SetKeyFlags(false, PgpKeyFlags.CanEncryptCommunications
| PgpKeyFlags.CanEncryptStorage);
masterSubpckGen.SetPreferredSymmetricAlgorithms(false,
(from a in keyRingParams.SymmetricAlgorithms
where a.IsSelected
select (int) a.Value).ToArray());
masterSubpckGen.SetPreferredHashAlgorithms(false,
(from a in keyRingParams.HashAlgorithms
where a.IsSelected
select (int) a.Value).ToArray());
/* Create the key ring. */
PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(
PgpSignature.DefaultCertification,
masterKeyPair,
keyRingParams.Identity,
keyRingParams.PrivateKeyEncryptionAlgorithm.Value,
keyRingParams.GetPassword(),
true,
masterSubpckGen.Generate(),
null,
new SecureRandom());
/* Add encryption subkey. */
keyRingGen.AddSubKey(encKeyPair, encSubpckGen.Generate(), null);
/* Generate the key ring. */
keyRingGen.GenerateSecretKeyRing();
The code works so far, the debug output also prints meaningful key IDs. 到目前为止,代码可以正常工作,调试输出还可以打印出有意义的密钥ID。 However, if I save the private key to a file and import it to GnuPG, it shows
sec 0s/FFFFFFFF 2013-07-30
for the master key. 但是,如果我将私钥保存到文件中并将其导入到GnuPG中,则主密钥显示为
sec 0s/FFFFFFFF 2013-07-30
。 The encryption key is OK. 加密密钥确定。
Edit: gpg --list-packet
shows 编辑:
gpg --list-packet
显示
:secret key packet:
version 4, algo 3, created 1375205303, expires 0
unknown algorithm 3
Algorithm 3 is PublicKeyAlgorithmTag.RsaSign
, which I assume is OK for a master key (the Java sample does that, too), but GnuPG does not like this... 算法3是
PublicKeyAlgorithmTag.RsaSign
,我认为对于主密钥是可以的(Java示例也可以),但是GnuPG不喜欢这样。
What am I doing wrong? 我究竟做错了什么?
Thanks in advance, Christoph 在此先感谢Christoph
In case someone else finds this useful for using BouncyCastle with C# (I just needed to do the same as above, but the code sample above was incomplete so I whipped up my own amateurish edited version). 万一其他人发现这对于将BouncyCastle与C#一起使用很有用(我只需要做与上面相同的操作,但是上面的代码示例不完整,所以我整理了自己的业余编辑版本)。 NOTE: This code was compiled and tested with LinqPad
注意:此代码是使用LinqPad编译和测试的
void Main()
{
String Password = "hello world!";
String Identity = "Slim Shady";
PgpKeyRingGenerator krgen = generateKeyRingGenerator(Identity, Password);
// Generate public key ring, dump to file.
PgpPublicKeyRing pkr = krgen.GeneratePublicKeyRing();
BufferedStream pubout = new BufferedStream(new FileStream(@"c:\temp\dummy.pkr", System.IO.FileMode.Create));
pkr.Encode(pubout);
pubout.Close();
// Generate private key, dump to file.
PgpSecretKeyRing skr = krgen.GenerateSecretKeyRing();
BufferedStream secout = new BufferedStream(new FileStream(@"c:\temp\dummy.skr", System.IO.FileMode.Create));
skr.Encode(secout);
secout.Close();
}
public static PgpKeyRingGenerator generateKeyRingGenerator(String identity, String password) {
KeyRingParams keyRingParams = new KeyRingParams();
keyRingParams.Password = password;
keyRingParams.Identity = identity;
keyRingParams.PrivateKeyEncryptionAlgorithm = SymmetricKeyAlgorithmTag.Aes128;
keyRingParams.SymmetricAlgorithms = new SymmetricKeyAlgorithmTag[] {
SymmetricKeyAlgorithmTag.Aes256,
SymmetricKeyAlgorithmTag.Aes192,
SymmetricKeyAlgorithmTag.Aes128
};
keyRingParams.HashAlgorithms = new HashAlgorithmTag[] {
HashAlgorithmTag.Sha256,
HashAlgorithmTag.Sha1,
HashAlgorithmTag.Sha384,
HashAlgorithmTag.Sha512,
HashAlgorithmTag.Sha224,
};
IAsymmetricCipherKeyPairGenerator generator
= GeneratorUtilities.GetKeyPairGenerator("RSA");
generator.Init(keyRingParams.RsaParams);
/* Create the master (signing-only) key. */
PgpKeyPair masterKeyPair = new PgpKeyPair(
PublicKeyAlgorithmTag.RsaSign,
generator.GenerateKeyPair(),
DateTime.UtcNow);
Debug.WriteLine("Generated master key with ID "
+ masterKeyPair.KeyId.ToString("X"));
PgpSignatureSubpacketGenerator masterSubpckGen
= new PgpSignatureSubpacketGenerator();
masterSubpckGen.SetKeyFlags(false, PgpKeyFlags.CanSign
| PgpKeyFlags.CanCertify);
masterSubpckGen.SetPreferredSymmetricAlgorithms(false,
(from a in keyRingParams.SymmetricAlgorithms
select (int) a).ToArray());
masterSubpckGen.SetPreferredHashAlgorithms(false,
(from a in keyRingParams.HashAlgorithms
select (int) a).ToArray());
/* Create a signing and encryption key for daily use. */
PgpKeyPair encKeyPair = new PgpKeyPair(
PublicKeyAlgorithmTag.RsaGeneral,
generator.GenerateKeyPair(),
DateTime.UtcNow);
Debug.WriteLine("Generated encryption key with ID "
+ encKeyPair.KeyId.ToString("X"));
PgpSignatureSubpacketGenerator encSubpckGen = new PgpSignatureSubpacketGenerator();
encSubpckGen.SetKeyFlags(false, PgpKeyFlags.CanEncryptCommunications | PgpKeyFlags.CanEncryptStorage);
masterSubpckGen.SetPreferredSymmetricAlgorithms(false,
(from a in keyRingParams.SymmetricAlgorithms
select (int) a).ToArray());
masterSubpckGen.SetPreferredHashAlgorithms(false,
(from a in keyRingParams.HashAlgorithms
select (int) a).ToArray());
/* Create the key ring. */
PgpKeyRingGenerator keyRingGen = new PgpKeyRingGenerator(
PgpSignature.DefaultCertification,
masterKeyPair,
keyRingParams.Identity,
keyRingParams.PrivateKeyEncryptionAlgorithm.Value,
keyRingParams.GetPassword(),
true,
masterSubpckGen.Generate(),
null,
new SecureRandom());
/* Add encryption subkey. */
keyRingGen.AddSubKey(encKeyPair, encSubpckGen.Generate(), null);
return keyRingGen;
}
// Define other methods and classes here
class KeyRingParams {
public SymmetricKeyAlgorithmTag? PrivateKeyEncryptionAlgorithm{ get; set; }
public SymmetricKeyAlgorithmTag[] SymmetricAlgorithms{ get; set; }
public HashAlgorithmTag[] HashAlgorithms{ get; set; }
public RsaKeyGenerationParameters RsaParams{ get; set; }
public string Identity{ get; set; }
public string Password{ get; set; }
//= EncryptionAlgorithm.NULL;
public char[] GetPassword() {
return Password.ToCharArray();
}
public KeyRingParams() {
//Org.BouncyCastle.Crypto.Tls.EncryptionAlgorithm
RsaParams = new RsaKeyGenerationParameters(BigInteger.ValueOf(0x10001), new SecureRandom(), 2048, 12);
}
}
To test this code, I just used another LinqPad script: 为了测试此代码,我只使用了另一个LinqPad脚本:
I still haven't done final tests on this, but it all seems to work (so far).
void Main() { PGPEncryptDecrypt pgp = new PGPEncryptDecrypt(); string passPhrase = "hello world!"; //full path to file to encrypt string origFilePath = @"c:\Temp\test.txt"; //folder to store encrypted file string encryptedFilePath = @"C:\Temp\Output\"; //folder to store unencrypted file string unencryptedFilePath = @"C:\Temp\Output\"; //path to public key file string publicKeyFile = @"c:\Temp\dummy.pkr"; //path to private key file (this file should be kept at client, AND in a secure place, far from prying eyes and tinkering hands) string privateKeyFile = @"c:\Temp\dummy.skr"; pgp.Encrypt(origFilePath, publicKeyFile, encryptedFilePath); pgp.Decrypt(encryptedFilePath + "test.txt.asc", privateKeyFile, passPhrase, unencryptedFilePath); } // Define other methods and classes here public class PGPEncryptDecrypt { public PGPEncryptDecrypt() { } /** * A simple routine that opens a key ring file and loads the first available key suitable for * encryption. * * @param in * @return * @m_out * @ */ private static PgpPublicKey ReadPublicKey(Stream inputStream) { inputStream = PgpUtilities.GetDecoderStream(inputStream); PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream); // // we just loop through the collection till we find a key suitable for encryption, in the real // world you would probably want to be a bit smarter about this. // // // iterate through the key rings. // foreach (PgpPublicKeyRing kRing in pgpPub.GetKeyRings()) { foreach (PgpPublicKey k in kRing.GetPublicKeys()) { if (k.IsEncryptionKey) { return k; } } } throw new ArgumentException("Can't find encryption key in key ring."); } /** * Search a secret key ring collection for a secret key corresponding to * keyId if it exists. * * @param pgpSec a secret key ring collection. * @param keyId keyId we want. * @param pass passphrase to decrypt secret key with. * @return */ private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec, long keyId, char[] pass) { PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId); if (pgpSecKey == null) { return null; } return pgpSecKey.ExtractPrivateKey(pass); } /** * decrypt the passed in message stream */ private static void DecryptFile(Stream inputStream, Stream keyIn, char[] passwd, string defaultFileName, string pathToSaveFile) { inputStream = PgpUtilities.GetDecoderStream(inputStream); try { PgpObjectFactory pgpF = new PgpObjectFactory(inputStream); PgpEncryptedDataList enc; PgpObject o = pgpF.NextPgpObject(); // // the first object might be a PGP marker packet. // if (o is PgpEncryptedDataList) { enc = (PgpEncryptedDataList)o; } else { enc = (PgpEncryptedDataList)pgpF.NextPgpObject(); } // // find the secret key // PgpPrivateKey sKey = null; PgpPublicKeyEncryptedData pbe = null; PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle( PgpUtilities.GetDecoderStream(keyIn)); foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects()) { sKey = FindSecretKey(pgpSec, pked.KeyId, passwd); if (sKey != null) { pbe = pked; break; } } if (sKey == null) { throw new ArgumentException("secret key for message not found."); } Stream clear = pbe.GetDataStream(sKey); PgpObjectFactory plainFact = new PgpObjectFactory(clear); PgpObject message = plainFact.NextPgpObject(); if (message is PgpCompressedData) { PgpCompressedData cData = (PgpCompressedData)message; PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream()); message = pgpFact.NextPgpObject(); } if (message is PgpLiteralData) { PgpLiteralData ld = (PgpLiteralData)message; string outFileName = ld.FileName; if (outFileName.Length == 0) { outFileName = defaultFileName; } Stream fOut = File.Create(pathToSaveFile + outFileName); Stream unc = ld.GetInputStream(); Streams.PipeAll(unc, fOut); fOut.Close(); } else if (message is PgpOnePassSignatureList) { throw new PgpException("encrypted message contains a signed message - not literal data."); } else { throw new PgpException("message is not a simple encrypted file - type unknown."); } if (pbe.IsIntegrityProtected()) { if (!pbe.Verify()) { Console.Error.WriteLine("message failed integrity check"); } else { Console.Error.WriteLine("message integrity check passed"); } } else { Console.Error.WriteLine("no message integrity check"); } } catch (PgpException e) { Console.Error.WriteLine(e); Exception underlyingException = e.InnerException; if (underlyingException != null) { Console.Error.WriteLine(underlyingException.Message); Console.Error.WriteLine(underlyingException.StackTrace); } } } private static void EncryptFile(Stream outputStream, string fileName, PgpPublicKey encKey, bool armor, bool withIntegrityCheck) { if (armor) { outputStream = new ArmoredOutputStream(outputStream); } try { MemoryStream bOut = new MemoryStream(); PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator( CompressionAlgorithmTag.Zip); PgpUtilities.WriteFileToLiteralData( comData.Open(bOut), PgpLiteralData.Binary, new FileInfo(fileName)); comData.Close(); PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator( SymmetricKeyAlgorithmTag.Cast5, withIntegrityCheck, new SecureRandom()); cPk.AddMethod(encKey); byte[] bytes = bOut.ToArray(); Stream cOut = cPk.Open(outputStream, bytes.Length); cOut.Write(bytes, 0, bytes.Length); cOut.Close(); if (armor) { outputStream.Close(); } } catch (PgpException e) { Console.Error.WriteLine(e); Exception underlyingException = e.InnerException; if (underlyingException != null) { Console.Error.WriteLine(underlyingException.Message); Console.Error.WriteLine(underlyingException.StackTrace); } } } public void Encrypt(string filePath, string publicKeyFile, string pathToSaveFile) { Stream keyIn, fos; keyIn = File.OpenRead(publicKeyFile); string[] fileSplit = filePath.Split('\\'); string fileName = fileSplit[fileSplit.Length - 1]; fos = File.Create(pathToSaveFile + fileName + ".asc"); EncryptFile(fos, filePath, ReadPublicKey(keyIn), true, true); keyIn.Close(); fos.Close(); } public void Decrypt(string filePath, string privateKeyFile, string passPhrase, string pathToSaveFile) { Stream fin = File.OpenRead(filePath); Stream keyIn = File.OpenRead(privateKeyFile); DecryptFile(fin, keyIn, passPhrase.ToCharArray(), new FileInfo(filePath).Name + ".out", pathToSaveFile); fin.Close(); keyIn.Close(); } }
\n\n\n\nMicrosoft.VisualBasic Org.BouncyCastle.Bcpg Org.BouncyCastle.Bcpg.OpenPgp Org.BouncyCastle.Bcpg.Sig Org.BouncyCastle.Crypto Org.BouncyCastle.Crypto.Generators Org.BouncyCastle.Crypto.Parameters Org.BouncyCastle.Math Org.BouncyCastle.Security System System.Collections System.IO
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.