簡體   English   中英

如何在沒有任何 API 的情況下生成 RSA 公鑰。 僅使用模數和公共指數

[英]How to generate RSA public key with no any API. Just using modulus and public exponent

如何在沒有任何 API 的情況下生成 RSA 公鑰。 僅使用模數和公共指數。

在我們的項目中,我們通過模數和公共指數實現 RSA PKCS#8 公鑰。 但是我們不知道 PKCS#8 公鑰的 ASN.1 二進制文件的含義。

為了理解 PKCS#8 公鑰 ASN.1,我們確實吹了。

 1. openssl genrsa -out hoge.key 2048  
 2. openssl rsa -pubout -in hoge.key  

Here we get below infomation.

> -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7z2oyePt5vNbH7Pbieiw
BOgRnCUyyUvUo6Wi+uqUWvMxrji1vH21ViTZYLjg40RrulSCGFwjzwnI4AMtEdIZ
7uOol12E3xOZYNgwTBaDNCT9p0IYYuFVGfQyxlavr7oSIaaNmlSRy+0os1xi7IiI
PCHE/7nfifDQiqGtb6b6TBOwP3QXg5IdrXiqQJAlk+8S0XPhbnwwzWOhlrR3Wftq
jylBPSGSDJQoF0fJ5h2cA2yJiGqTV37YRTThPWmQEuz8Njx4bTaEaTul5/UNhSel
s7khd/IvHV9oN6T2o4V//fAsyjRZlYKEUHldb3ML/QHxWs7+hqWSa9NCwwXZGhEl
wwIDAQAB
-----END PUBLIC KEY-----

> 0000000 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01
0000010 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01
0000020 00 ef 3d a8 c9 e3 ed e6 f3 5b 1f b3 db 89 e8 b0
0000030 04 e8 11 9c 25 32 c9 4b d4 a3 a5 a2 fa ea 94 5a
0000040 f3 31 ae 38 b5 bc 7d b5 56 24 d9 60 b8 e0 e3 44
0000050 6b ba 54 82 18 5c 23 cf 09 c8 e0 03 2d 11 d2 19
0000060 ee e3 a8 97 5d 84 df 13 99 60 d8 30 4c 16 83 34
0000070 24 fd a7 42 18 62 e1 55 19 f4 32 c6 56 af af ba
0000080 12 21 a6 8d 9a 54 91 cb ed 28 b3 5c 62 ec 88 88
0000090 3c 21 c4 ff b9 df 89 f0 d0 8a a1 ad 6f a6 fa 4c
00000a0 13 b0 3f 74 17 83 92 1d ad 78 aa 40 90 25 93 ef
00000b0 12 d1 73 e1 6e 7c 30 cd 63 a1 96 b4 77 59 fb 6a
00000c0 8f 29 41 3d 21 92 0c 94 28 17 47 c9 e6 1d 9c 03
00000d0 6c 89 88 6a 93 57 7e d8 45 34 e1 3d 69 90 12 ec
00000e0 fc 36 3c 78 6d 36 84 69 3b a5 e7 f5 0d 85 27 a5
00000f0 b3 b9 21 77 f2 2f 1d 5f 68 37 a4 f6 a3 85 7f fd
0000100 f0 2c ca 34 59 95 82 84 50 79 5d 6f 73 0b fd 01
0000110 f1 5a ce fe 86 a5 92 6b d3 42 c3 05 d9 1a 11 25
0000120 c3 02 03 01 00 01                              
0000126

我們理解上面的二進制如下。 但是我們不了解一些二進制文件。所以我們想知道PKCS#8公鑰的ASN.1二進制文件的含義。 順便說一下,我們已經參考了以下信息。 然而,這並沒有提到公鑰。 https://datatracker.ietf.org/doc/html/rfc5208

30: SEQUEENCE
82: next 2byte is sequence length 
01 22: 0x122byte
30: SEWUENCE
0d:?
06:?
09:?
2a 86.. 01 01 01: PKCS#1 rsa Encryption
05: ?
00: ?
03: ?
82: next 2byte is length of bit string
01 0f: length of bit string
00: ?
30 82....: PKCS#1 public key

賭一把,你真正想問的是如何從 RSA 公鑰 PEM 編碼中獲取模數和公共指數,我邀請你參加這次幽會。 如果您希望僅在給定模數和公共指數的情況下構建此編碼,則此剖析應向您展示它的布局方式,這是實現目標的有點反向的路線圖。 無論哪種方式,請繼續閱讀。

首先: “下一個 2byte 是位串的長度” - 這是你的假設。 ASN.1 完全是關於類型-長度-值(簡稱 TLV)並且不會從該模型中動搖 “接下來的 2 個字節是位串的長度”的唯一原因是因為 ASN.1 說它是。 (稍后會詳細介紹)。

ASN.1 非常靈活。 我最近有一位同事開玩笑地告訴我“ASN.1 只是嬰兒潮一代的 JSON”。 是的,我個人認為。 自從 JSON 跟隨 ASN.1 幾十年以來,我喜歡認為“JSON 只是千禧一代的 ASN.1”。

無論如何,關於 ASN.1(和 JSON,就此而言)的有趣之處在於:有時 TLV 編碼中有 TLV 編碼,這里就是這種情況。 具體來說,如果設置正確(即 OID 匹配),則 RSAPublicKey 序列將被編碼為 ASN.1 位字符串,這似乎是您正在努力解決的問題:如何找到它。

我將留下實際代碼來執行此操作(這將是乏味的,毫無疑問充滿黑客,最終會讓您希望您剛剛使用了加密庫)作為一項任務。 也就是說,繼續撕開你的公鑰的行為。 首先,您的 PEM:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7z2oyePt5vNbH7Pbieiw
BOgRnCUyyUvUo6Wi+uqUWvMxrji1vH21ViTZYLjg40RrulSCGFwjzwnI4AMtEdIZ
7uOol12E3xOZYNgwTBaDNCT9p0IYYuFVGfQyxlavr7oSIaaNmlSRy+0os1xi7IiI
PCHE/7nfifDQiqGtb6b6TBOwP3QXg5IdrXiqQJAlk+8S0XPhbnwwzWOhlrR3Wftq
jylBPSGSDJQoF0fJ5h2cA2yJiGqTV37YRTThPWmQEuz8Njx4bTaEaTul5/UNhSel
s7khd/IvHV9oN6T2o4V//fAsyjRZlYKEUHldb3ML/QHxWs7+hqWSa9NCwwXZGhEl
wwIDAQAB
-----END PUBLIC KEY-----

將base64解碼為DER,然后通過xxd顯示,長這樣:

00000000: 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01  0.."0...*.H.....
00000010: 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01  ........0.......
00000020: 00 ef 3d a8 c9 e3 ed e6 f3 5b 1f b3 db 89 e8 b0  ..=......[......
00000030: 04 e8 11 9c 25 32 c9 4b d4 a3 a5 a2 fa ea 94 5a  ....%2.K.......Z
00000040: f3 31 ae 38 b5 bc 7d b5 56 24 d9 60 b8 e0 e3 44  .1.8..}.V$.`...D
00000050: 6b ba 54 82 18 5c 23 cf 09 c8 e0 03 2d 11 d2 19  k.T..\#.....-...
00000060: ee e3 a8 97 5d 84 df 13 99 60 d8 30 4c 16 83 34  ....]....`.0L..4
00000070: 24 fd a7 42 18 62 e1 55 19 f4 32 c6 56 af af ba  $..B.b.U..2.V...
00000080: 12 21 a6 8d 9a 54 91 cb ed 28 b3 5c 62 ec 88 88  .!...T...(.\b...
00000090: 3c 21 c4 ff b9 df 89 f0 d0 8a a1 ad 6f a6 fa 4c  <!..........o..L
000000a0: 13 b0 3f 74 17 83 92 1d ad 78 aa 40 90 25 93 ef  ..?t.....x.@.%..
000000b0: 12 d1 73 e1 6e 7c 30 cd 63 a1 96 b4 77 59 fb 6a  ..s.n|0.c...wY.j
000000c0: 8f 29 41 3d 21 92 0c 94 28 17 47 c9 e6 1d 9c 03  .)A=!...(.G.....
000000d0: 6c 89 88 6a 93 57 7e d8 45 34 e1 3d 69 90 12 ec  l..j.W~.E4.=i...
000000e0: fc 36 3c 78 6d 36 84 69 3b a5 e7 f5 0d 85 27 a5  .6<xm6.i;.....'.
000000f0: b3 b9 21 77 f2 2f 1d 5f 68 37 a4 f6 a3 85 7f fd  ..!w./._h7......
00000100: f0 2c ca 34 59 95 82 84 50 79 5d 6f 73 0b fd 01  .,.4Y...Py]os...
00000110: f1 5a ce fe 86 a5 92 6b d3 42 c3 05 d9 1a 11 25  .Z.....k.B.....%
00000120: c3 02 03 01 00 01                                ......

正如預期的那樣,常規 ASN.1 編碼。 對於 PKCS8 編碼的密鑰,它應該如下所示:

PublicKeyInfo ::= SEQUENCE {
  algorithm       AlgorithmIdentifier,
  PublicKey       BIT STRING
}

通過 ASN.1 解碼發送 base64 解碼的 DER 數據,我們看到:

openssl asn1parse -in pubkey.der -inform DER

    0:d=0  hl=4 l= 290 cons: SEQUENCE          
    4:d=1  hl=2 l=  13 cons: SEQUENCE          
    6:d=2  hl=2 l=   9 prim: OBJECT            :rsaEncryption
   17:d=2  hl=2 l=   0 prim: NULL              
   19:d=1  hl=4 l= 271 prim: BIT STRING        

這看起來是對的。 對於 RSA 公鑰,OID 是 1.2.840.113549.1.1.1,NULL,那么應該是 RSAPublicKey 作為 PublicKey 密鑰數據位串,如下所示:

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e
}

從上述解碼中,我們知道偏移量 19 是實際的位串,它應該包含 RSAPublicKey ASN.1 結構。 很好,但如何? 好吧,原始解析在文件的 offset-19 處具有以下內容:

00000010: 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01  ........0.......
                   ^^^^^^^^^^^^^^

由此我們得到:

  • ASN.1 標記字節03表示它是一個位串。 好的。 我們預料到了。 然后...
  • 計算長度。 根據 ASN.1 規則,如果長度八位字節的高位亮起,則意味着該八位字節的剩余位告訴有多少后續八位字節構成實際長度(即它可以是多字節長度)。 82表示010f跟着兩個八位字節,表示位串總對象長度: 010f ,例如 271 字節。
  • 緊跟在長度描述之后的將是單個八位字節,說明位串的填充位數 老實說,在盯着這些的四分之一個世紀里,我從未在任何 RSA 編碼的公鑰中看到過除零 ( 00 ) 以外的任何值,但仍然值得一提。

此后是實際的 RSAPublicKey ASN.1 結構本身。 通過位串類型長度填充描述,我們可以解析實際的 RSAPublicKey(終於!)。 類型長度和填充位指示符后面的位串內容應該就是這樣。 好吧,那是我們 DER 編碼的偏移量 24,所以:

openssl asn1parse -in pubkey.der -inform DER -offset 24

    0:d=0  hl=4 l= 266 cons: SEQUENCE          
    4:d=1  hl=4 l= 257 prim: INTEGER           :EF3DA8C9E3EDE6F35B1FB3DB89E8B004E8119C2532C94BD4A3A5A2FAEA945AF331AE38B5BC7DB55624D960B8E0E3446BBA5482185C23CF09C8E0032D11D219EEE3A8975D84DF139960D8304C16833424FDA7421862E15519F432C656AFAFBA1221A68D9A5491CBED28B35C62EC88883C21C4FFB9DF89F0D08AA1AD6FA6FA4C13B03F741783921DAD78AA40902593EF12D173E16E7C30CD63A196B47759FB6A8F29413D21920C94281747C9E61D9C036C89886A93577ED84534E13D699012ECFC363C786D3684693BA5E7F50D8527A5B3B92177F22F1D5F6837A4F6A3857FFDF02CCA345995828450795D6F730BFD01F15ACEFE86A5926BD342C305D91A1125C3
  265:d=1  hl=2 l=   3 prim: INTEGER           :010001

果然,就是預期的模數和指數。 從那里提取和解碼只是代碼問題,但至少現在是基於計算解碼而不是猜測的代碼。

公平警告

這樣做的唯一原因是因為我們知道 RSAPublicKey 在位字符串中,我們知道的唯一原因是因為 OID 說它是。 存儲在比特串的形式是依賴於OID,所以首先要確保假定位串前要檢查它RSAPublicKey材料。

您問的是如何生成公鑰,但我不明白您為什么要顯示一些要解碼的二進制數據。 您無法通過查看我認為已經加密的二進制數據來學習如何生成公鑰或私鑰。 為什么不使用庫來生成密鑰對並完成它呢? 嘗試自己從頭開始編寫代碼很可能(實際上很可能)會出現錯誤,從而導致非常不安全的情況。 無論如何,如果您想看看可以從它們中學到什么,您可以將源代碼下載到像 openssl 這樣的 ssl 庫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM