PGP 數位簽章以及數位認證 ( Sign and Verify ),是市面上常見用來判斷資訊是否源自正確的來源方式之一。 Bouncy Castle 也提供了這項功能。
最常見的數位簽章認證流程通常為 資料來源方 利用自己的 Private Key 對傳送的檔案 or 資訊做數位簽章動作,證明此資訊由自己發送。接收方 則利用 資料來源方的 Public Key 來做數位認證動作,證實來源無誤。
而本篇文章是講如何先用 Bouncy Castle API 利用 Private Key 對檔案做數位簽章,接著在用 Public key 做數位認證動作。
1. 此部分一樣需要官方範例中 PgpExampleUtilities.cs 檔案 ( bccrypto-net-1.7-src\csharp\crypto\test\src\openpgp\ examples),加入專案中。此Class 提供取出private 以及 public key 資訊的 method 。
2. Bouncy Castle 之 Private Key 檔案數位簽章 SignFile method 實作如下:
private static void SignFile( string fileName, //預作簽章的檔案名稱及位置 Stream keyIn, // Private key 的 File Stream Stream outputStream, //簽章後的檔案 File Stream char[] pass, // private Key 的 password bool armor, //用途不明?? 範例預設true bool compress //用途不明?? 範例預設true ) { if (armor) { outputStream = new ArmoredOutputStream(outputStream); } PgpSecretKey pgpSec = PgpExampleUtilities.ReadSecretKey(keyIn); PgpPrivateKey pgpPrivKey = pgpSec.ExtractPrivateKey(pass); PgpSignatureGenerator sGen = new PgpSignatureGenerator(pgpSec.PublicKey.Algorithm, HashAlgorithmTag.Sha1); sGen.InitSign(PgpSignature.BinaryDocument, pgpPrivKey); foreach (string userId in pgpSec.PublicKey.GetUserIds()) { PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator(); spGen.SetSignerUserId(false, userId); sGen.SetHashedSubpackets(spGen.Generate()); // Just the first one! break; } Stream cOut = outputStream; PgpCompressedDataGenerator cGen = null; if (compress) { cGen = new PgpCompressedDataGenerator(CompressionAlgorithmTag.ZLib); cOut = cGen.Open(cOut); } BcpgOutputStream bOut = new BcpgOutputStream(cOut); sGen.GenerateOnePassVersion(false).Encode(bOut); FileInfo file = new FileInfo(fileName); PgpLiteralDataGenerator lGen = new PgpLiteralDataGenerator(); Stream lOut = lGen.Open(bOut, PgpLiteralData.Binary, file); FileStream fIn = file.OpenRead(); int ch = 0; while ((ch = fIn.ReadByte()) >= 0) { lOut.WriteByte((byte)ch); sGen.Update((byte)ch); } fIn.Close(); lGen.Close(); sGen.Generate().Encode(bOut); if (cGen != null) { cGen.Close(); } if (armor) { outputStream.Close(); } }
3. Bouncy Castle 之 Public Key 檔案數認證 VerifyFile method 實作如下:
private static void VerifyFile( Stream inputStream, //準備做數位認證檔案的 File Stream Stream keyIn, // Public Key 的 File Stream string outputFileName // 將數位簽章清除後產生未簽章之原始黨 ) { inputStream = PgpUtilities.GetDecoderStream(inputStream); PgpObjectFactory pgpFact = new PgpObjectFactory(inputStream); PgpCompressedData c1 = (PgpCompressedData)pgpFact.NextPgpObject(); pgpFact = new PgpObjectFactory(c1.GetDataStream()); PgpOnePassSignatureList p1 = (PgpOnePassSignatureList)pgpFact.NextPgpObject(); PgpOnePassSignature ops = p1[0]; PgpLiteralData p2 = (PgpLiteralData)pgpFact.NextPgpObject(); Stream dIn = p2.GetInputStream(); PgpPublicKeyRingBundle pgpRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn)); PgpPublicKey key = pgpRing.GetPublicKey(ops.KeyId); //add Stream fileOutput = File.Create(outputFileName); ops.InitVerify(key); int ch; while ((ch = dIn.ReadByte()) >= 0) { ops.Update((byte)ch); fileOutput.WriteByte((byte)ch); } fileOutput.Close(); PgpSignatureList p3 = (PgpSignatureList)pgpFact.NextPgpObject(); PgpSignature firstSig = p3[0]; if (ops.Verify(firstSig)) { Console.Out.WriteLine("signature verified."); } else { Console.Out.WriteLine("signature verification failed."); } }
我們有了數位簽章 以及數位認證兩個 method 後,接著就列出簡單的程式實作,對 A檔案 作數位簽章產生 B檔案, 解著在對 B檔案 做是為認證,成功後產生 C檔案。而理論上 A C檔案內容應該會一致。其實作程式如下:
static void Main(string[] args) { //private2 對檔案做數位簽章 string fileName = @"D:/BC/a.txt"; Stream signkeyIn = File.OpenRead(@"D:/BC/priv.asc"); Stream signOutputStream = File.Create(@"D:/BC/b.txt"); char[] signPass = "123456".ToCharArray(); bool signArmor = true; bool compress = true; try { SignFile(fileName, signkeyIn, signOutputStream, signPass, signArmor, compress); Console.WriteLine("簽章成功"); } catch (Exception e) { Console.WriteLine("簽章失敗" + e.Message); } finally { signkeyIn.Close(); signOutputStream.Close(); } //public2 對檔案做數位認證 Stream inputStream = File.OpenRead(@"D:/BC/b.txt"); Stream keyIn = File.OpenRead(@"D:/BC/pub.asc"); string outputFileName = @"D/BC/c.xml"; try { VerifyFile(inputStream, keyIn, outputFileName); Console.WriteLine("認證OK"); } catch (Exception e) { Console.WriteLine("認證失敗" + e.Message); } Console.Read(); }
這樣我們就完成一個簡單利用 Bouncy Castle 實作的的數位簽章、數位認證的範例了。
沒有留言:
張貼留言