Reference-Request

如何為 PGP 公鑰生成指紋

  • January 23, 2016

我想知道如何為 openPGP 公鑰生成指紋。

需要明確的是,我對如何生成指紋感興趣。我知道我可以使用命令行工具獲取指紋。

我在這裡查閱了 PGP 文件,但無法重現我感興趣的密鑰的已知指紋。

我試圖指紋的關鍵是:

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: Keybase OpenPGP v2.0.49
Comment: https://keybase.io/crypto

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
6RZ7aOZsD4ZW
=/HI0
-----END PGP PUBLIC KEY BLOCK-----

keybase.io上,指紋給出為

07DBC7442CABB41ADCB031E03103E62B81D9EB52

再說一遍:我對如何生成指紋感興趣(而不是如何使用 PGP 軟體)。

您的指紋與 OpenPGP V4 兼容,因為它使用 SHA-1。指紋是 20 個字節,而不是舊包格式中使用的 MD5 的 16 個字節。

對於 V4,需要先提取公鑰。這可能是最棘手的部分,因為 PGP 使用它自己的數據包格式。您必須解析 base 64 編碼 blob 中的二進制數據才能找到數據包。

這來自RFC 4880:OpenPGP 標準,第 12.2 節

V4 指紋是八位字節的 160 位 SHA-1 雜湊0x99,後跟兩個八位字節的數據包長度,然後是從版本欄位開始的整個公鑰數據包。Key ID 是指紋的低 64 位。

Java 源的 Bouncy Castle 僅在以下內容中聲明JcaKeyFingerprintCalculator

byte[]             kBytes = publicPk.getEncodedContents();

MessageDigest   digest = MessageDigest.getInstance("SHA1");

digest.update((byte)0x99);
digest.update((byte)(kBytes.length >> 8));
digest.update((byte)kBytes.length);
digest.update(kBytes);

return digest.digest();

在哪裡publicPk並且kBytes已經包含已解析的數據包。

所以你必須使用pre-V4 編碼長度,即16 位大端整數編碼。


在上述情況下,公鑰數據包位於位置 [3, 528)。


查找數據包位置的有趣蠻力方法:

String base64Key = "xsFNBFaVsC8BEADPvQH7xlfx2HJf7wQjPkFpkRCGSWR+lSo+cS3Ci81HcguLqt/l"
       ....
       + "6RZ7aOZsD4ZW";
// note: don't include the checksum at the end, after and including the `=` sign.   

byte[] decodedKey = Base64.decode(base64Key);

System.out.println(decodedKey.length);

ByteBuffer encodedLength = ByteBuffer.allocate(2);

MessageDigest digest = MessageDigest.getInstance("SHA1");

int startOff = 0;
for (startOff = 0; startOff < decodedKey.length; startOff++) {
   for (int endOff = decodedKey.length; endOff > startOff; endOff--) {
       encodedLength.putShort(0, (short) (endOff - startOff));
       
       digest.update((byte) 0x99);
       digest.update(encodedLength.array());
       digest.update(decodedKey, startOff, endOff - startOff);
       byte[] fingerPrint = digest.digest();
       String hexFingerPrint = Hex.toHexString(fingerPrint);
       if (hexFingerPrint
               .equalsIgnoreCase("07DBC7442CABB41ADCB031E03103E62B81D9EB52")) {
           System.out.printf("%d - %d%n", startOff, endOff);
           return;
       }
   }
}

引用自:https://crypto.stackexchange.com/questions/32087