RSA 中的指數和模數以及 DSS 中的 y、p、q、g 的最大大小
我正在用 Java 編寫一個方法來讀取RFC 4253格式的 SSH 公鑰,在我的例子中,它可以是 RSA 或 DSS。
我真正需要的是讀取
exponent
和modulus
RSA 密鑰和DSS 密鑰的y
,p
,q
,g
值,根據標準是類型mpint
(多精度整數)。所以基本上,我正在做的是首先讀取一個整數(變成“長度”),然後讀取與該整數一樣多的字節,然後將該字節數組轉換為 Java 的
BigInteger
.它適用於有效密鑰。但是,如果有一個格式錯誤的密鑰,其中第一個整數是一個非常大的數字(比如說
Integer.MAX_VALUE
),就會出現問題。然後這種方法會導致Requested array size exceeds VM limit
異常或其他一些與記憶體相關的 Java 錯誤。我想要解決這個問題是預先檢查長度整數是否在有效範圍內(小於某個最大值)。
exponent
問題來了: 、modulus
、y
、和的最大值是p
多少?他們甚至有最大值嗎?q``g
密碼系統本身沒有限制。您可以使用具有任何類型密鑰大小的 DSA 或 RSA 系統。
但是,生成超過 16Ki 的 DSA 域參數或生成大小超過 16Ki 的 RSA 密鑰是非常消耗 CPU 的操作。我的電腦在我輸入時生成了一個 17Ki RSA 密鑰對,只是為了給 bartonjs 另一個軼事告訴他的孫子們一次;)
啊,就是這樣,模數是(十六進制):
ba948ca14989fa57a16d492243a9be9452f54d6d5f568956c246f8ecfe8e7a04a9cd827314f0c8d70e99c02fc01546ee70ed2a0222ac909d6f8f0f8e5a10838173daf9903bdab2587e57be5bfbe5a1f1161e3b2b8361562adcf36fa4d94c4f145bcb3de1fdf44715fc64611eee3925e9f06734065dee2a9c970a33f62adf385f683d71c5d6cb9a1dbeba801feefb3edacdc13d3ddcc41b8b1f91ee84fdec758e1fedca74684ace88b1e28f79ef0b3381384b1f4339751875098b584b85d04576d7e4755e537b877e033b6c5726f1896aa5e5c635875b9499d3515e618e08001a4e3516aa687cbf55ffa94f1e6e978ebc7dfd5bf7e11fa045339cda817413a7674a73e53b00270d880bd73d236422ba8a5fd48bec4686ac9d0e0d8641e1451a8fef69607cfa3d1a2ffcb2a24edcd3d1dc028e6a14aed9dca587fc8d79fb9c3c8759ec8924aa9f3abedd7b986491e2fed16d445430339f45e433d46cbdf94e929748a8544de973cbe3aa67285c38787b9e45f2ce64a58b7d78078141c584905611b63a6f438efd4ed52d161568b57b39db4b4391f35b2fea1ff52bc0ff79fd2cd8cd069f0e20b4ed06f16909983d9f46416ef2775dddf4d4a120f99c7baee0b2a06be383579f13093c3f3e62508955462e5ceefda4483a75f1b03badce08ee26283195c1072844f19d0156e7527b3df2615938f14e22259fa14d04292c2367a94814711b396716f5911faef248c520b9b4410a53dac5c6d19f382f02a25607032a2745dfb1f647a28a3d403562f177996c4c6657a0db2d3cf0bfc84af69e1b607552a242ea07e89f2281c4040844cfae816a0111fdc8ff570b3facb669fefcfacd5812d9eb46131e20c106ec8bf70668b1d6b61bd72f9aaabb22bd4f3fdbbf060f894ac8a919f61c7fc46ef091c3523c902c1fd961dbddfc6df9a7e0d2f68cd04a0698aa0db465e05d74c0b906cdb0f27b31df2c43f59ef04b1f791f360a8e4d3ffb0a6ab38d5075171139268ed749263c5dd1618b6c243f823c7a982755bb990dc6270cc84867c58de4086ed05a8c5fabaaa0c34d79d4820b37afc47b8bcc08e4729620ef46ed192c7c17cce0afedb707143d7161f586680356f6e596482a317b20e44f486504cc78b0c692253c6230f35dd5998d84ab2b03ada45a90bed258db611a5583995b4b1c10023d8875c9d1e4ddcfa7ab834a0bed9161eaf187f21409d0168cce2dc0965188e2c67967c1557b90e806f5af45191cc2cdf5ec93892aec5d32fe380d1c57ec4fd9696a05a1bea22199e490c0a03829eebbf32cd7cf7cb5507c90a9c6e066f1381754e6a7319d8d5931ebc23239165b632f4e59feabf1dea6bcea421ff1ab891735ca11082f4126fe696dd16e751521db92f502339e567cbb1b335688f83ba1e6bf8ec0926b79a2f09ffc462c5ceddcbaa71aaa24662d7cd319dd4194b48eaa8f5fb5c340fd96ad4b8db57e856a4d971beec6eff512ebc41d0887392c77c7318ae182a4be13563ac2e67b7c4ebb1f3b3e8d3ce9da3bf5e643bc1e0da91bd208a90f5a3df8e1184bf1ce7b4c7c4aaec85491fb7f7844df26240e6f7e2a90d6cab247dbfd35f839d9773b5501df43134788421023b1592d0da1994f722903c83e91f2d1f3adeade9aa7c0deaa38c0768bde2d6338091e8c51718d39050ff18d1d115bf55b292e0a70dc6c0f35fd519b858869744dd4276a20584532117b436aab0fd9c8580dfbd30755e6a4518a48f32bba63450b597d4e1229baa3821cd819e811b3fd05b702bb99d7f6ddb601e579fdd43bdb4e950b6be66e68c3c5ffd1ebbe75e2e80fefd786718d9dc4ce7ef522bd9988201e874993cd84db9591182817f18ccf4c0f1dff89dd548b57b680eab917b67b76ae7daab46f4feeb5c533cbad3b0187ffbccb479e30510a9e99b5a4696ab58986d681837806f17ef2c698a5dba8a3ad099b96e6483d0445c42a97c8e2f139fcb26c3120c3a4ac9a43443de7603cf47701db975c5687aaabf3d52953c5e63cc2984b4b995dbdf2827d6c2d2862ef51eb7e958c6b6eac6ef0d30bee671f9c251912d964cfbfd5c535d1d6f5951795cf2d43da776f63e5b42abc0885fa59a4554988d7d7e24b054e7aac3946ba4f438927a21b2e9e388d357229e7bea9c3fe8d3d560d605e16a2d364b6cac7868e148dc158b50b6fe592eae7a016b9adc7e5b251a6c9cd32cc9d271366c003975f21b52c0f03badf481ee7000e74b1abfd267ef42e4cd1c53a80ff44c9e0c68291575c4eb876751c701da70fbf8a43f8312f68cc866bdd4b14d3e9a475505dda90c467b687562fcd6b9d79bfafce27d6dcaa7f89790a26e754251466d7d3a45a9472e1b32aa3b56b96f9a0bcc3ca7226ddcd528ac8666c9e661d408f8a87a218ab5a41b5fb332ba2caf02778f2942659c8542581cecf7dfb337c8f81343a1778976c30472f95d759fdf43ec1e4fe8d68ed3b1f4fe8959c4eccc51eb6bff2ad29bb41142c58482acd8dedaae37a2f02610848b87007f290a6385d479cc55c83933f2cb4daf5ef85846d0cb4176b27464c7942ddd8357e38fcfc434667e6d2851a10d19b5fc3553269fc8de342c485aa59941e4b810457902e9830cfdf3f3ca1cd5026f2c716a954ec1b7248d59df382d270c712c81f0997099187bddb6620bb982333449c84f9a4340b3d639edf9b66ebdd966ae919b37c462e64f75b96767f5473178bee02c648f12857ffc692d805ac7523ff978c5b0bed858dc01a5b25ead826fe34c9c2b4a437b7b60227f3fd190e38d01ce08e52502d54642bc80054bcf155423e9faacffa8d6d409610f8b2c71c14f8d625c78d54a5f0db76c5e23e10dd5d3874ebbe7db5a36021c341b8d56362ee4a5ba89ecef3ad4b9d06701fe09c460f34893fe8008e3cc487f3ac0bce387d77afbce666002565e514a2ba61cb29652a2d5bcdb21167a2f2e3ae1eb459d6e457565e73f203ca34995f37db4d949761d7f0778bce198a1f2978c02f8f631656ecc10e2eac3029ded2598d544020dd78ebb61d13b373498039e122dbdb0b45850cb416b748ee60034727
但是,出於實際目的,bartonjs 提出的 4Ki 和 16 Ki 限制就可以了。
如果您只支持 8 甚至 32 的倍數的密鑰大小,那麼沒有人會嫉妒您;有很多實現可以做到這一點;很少有人會支持密鑰大小不能被 8 整除的 RSA,即使這是完全可能的。
對於 SSH 協議,您必須查看指定數據類型的 RFC 4251 的第 5 節。這
mpint
是一個編碼為類型的有符號大端值string
。這種string
類型本身是一個八位字節字元串(Java 中的字節數組),前面是一個編碼長度的無符號 32 位整數。這意味著
00
模數左側將需要一個有價值的填充字節。因此,您應該為每個數字允許 16Ki / 8 = 2Ki 字節加上一個填充字節(不包括用於編碼mpint
自身大小的 4 字節成本)。這裡 1Ki = 1024 字節(所以 2Ki + 1= 2049 字節將是數字的總大小)。請注意,RSA 簽名被編碼為無符號八位字節字元串,因此 16Ki 簽名只需要 2Ki 字節。
例如,您可以將值 2049 作為值
mpIntMaxBytes
:/** * Parses the <code>mpint</code> (multi-precission integer) SSH type * specified in RFC 4251 section 5. This method advances the position in the * buffer to the byte after the parsed <code>mpint</code>. If a * {@link SSHDataParseException} occurs then the buffer will have advanced * an unspecified number of times. * * @param buf * the buffer that contains the <code>mpint</code> encoding from * the current position * @param mpIntMaxBytes * the maximum number of bytes that the signed encoding of the * <code>mpint</code> may use * @return the <code>mpint</code> as BigInteger * @throws SSHDataParseException * if the <code>mpint</code> encoding is too large or if it is * empty */ public BigInteger parseMPInt(ByteBuffer buf, int mpIntMaxBytes) throws SSHDataParseException { if (mpIntMaxBytes < 1) { throw new IllegalArgumentException( "maxBytes should be larger than 0 to contain an mpint"); } long mpIntSize = parseStringSize(buf); if (mpIntSize == 0) { throw new SSHDataParseException( "A number consists of at least 1 byte (00h represents zero)"); } if (mpIntSize > mpIntMaxBytes) { throw new SSHDataParseException("Number exceeds maximum size"); } // get mpint from the buffer using newly generated array (BigInteger // does not allow reading from a specific offset) byte[] mpIntBuf = new byte[(int) mpIntSize]; buf.get(mpIntBuf); // an mpint is a signed big endian byte array, just like the default // BigInteger encoding return new BigInteger(mpIntBuf); } /** * Parses the size of the (octet) string, where the size of the string is a * 32 bit uint. * * @param buf * the buffer that contains the size encoding from the current * position * @return the size as a value between 0 and 2^32 - 1 */ public long parseStringSize(ByteBuffer buf) { return buf.getInt() & 0xFFFFFFFF; } public static class SSHDataParseException extends Exception { private static final long serialVersionUID = 1L; public SSHDataParseException(String message) { super(message); } }
請注意,此程式碼仍然不檢查返回
BigInteger
是正數還是負數、特定位大小,也不檢查是否使用了最小編碼。解析正在驗證,直到您看到疲憊時出現藍色,恐怕。更糟糕的是,這是未經測試的程式碼,祝你好運!