簡體   English   中英

提取存儲在無符號char數組中的RSA公鑰模數和指數

[英]Extracting RSA public key modulus and exponent stored in unsigned char arrays

因此,我正在使用一個專有的庫,該庫具有用於創建RSA密鑰對的自己的實現。 公鑰結構如下所示:

typedef struct
{
   unsigned int bits;                         //Length of modulus in bits
   unsigned char modulus[MAX_RSA_MOD_LEN];    //Modulus
   unsigned char exponent[MAX_RSA_MOD_LEN];   //Exponent
} RSA_PUB_KEY

我需要找出一種提取指數和模塊的方法,以便將它們作為驗證方案的一部分發送到服務器。 我想這是一個非常標准的過程(或者我希望如此)。 我已經閱讀了以下兩個類似的問題:

但是到目前為止,我還沒有運氣。 我也不確定如何在必要時使用“位”字段提取模數。 簡而言之,我要做的就是能夠在Java中重新創建此公鑰:

BigInteger m = new BigInteger(MODULUS); 
BigInteger e = new BigInteger(EXPONENT);

RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);

return pubKey;

編輯:

這就是我現在正在做的:(RSAPublic是如上所述的RSA_PUB_KEY結構)。

//RSAPublic.bits = length of modulus in bits                
log("Modulus length: "+std::to_string(RSAPublic.bits));
log("Key length: "+std::to_string(keyLengthInBits));

//Calculating buffer size for converted hexadec. representations
int modulusLengthInBytes = (RSAPublic.bits+7)/8 ;
int exponentLengthInBytes = (keyLengthInBits+7)/8;

char convertedMod[modulusLengthInBytes*2+1];
char convertedExp[exponentLengthInBytes*2+1];

//Conversion
int i;
for(i=0; i<modulusLengthInBytes ; i++){
  sprintf(&convertedMod[i*2], "%02X", RSAPublic.modulus[i]);
}
for(i=0; i<exponentLengthInBytes ; i++){
  sprintf(&convertedExp[i*2], "%02X", RSAPublic.exponent[i]);
}

//Print results
printf("Modulus: %s\n", convertedMod);  
printf("Exponent: %s\n", convertedExp); 

這是輸出:

Modulus length: 16
Key length: 512
Modulus: 0000
Exponent: 0A000200FFFFFFFFFFFF0000600007004DDA0100B01D0000AEC642017A4513000000000000000000000000000000000000000000000000000000000000000000

我假設您不能只發送二進制數據,因為您提到了十六進制轉換。 以文本形式發送數據的最緊湊的方式是使用base 64,但這比十六進制要復雜。

客戶端

使用您擁有的鏈接中的方法將無符號char數組轉換為十六進制字符串。 bits字段將確定要使用(bits+7)/8的數組中要使用的字節數。

根據實現的不同,您可能必須顯式地選擇溢出位,或者將其余的位清零,這也取決於字節序,因此,由於不確定實現的細節,您可能需要對其進行一些調整。

獲得編碼字符串后,將它們發送到服務器。

服務器端

從連接中讀取編碼的字符串,然后使用十六進制(16)的基數將它們傳遞給BigInteger(String val, int radix)構造函數。

然后,您將獲得一個具有所需值的BigInteger

如果公共指數的第一個字節全為零,那么您正在處理一個大端數組。 這是最常見的。 原則上,公共指數可以與模數一樣大,但是通常不是這種情況。 最常見的值是65537、17和3,甚至可能是2,但是3和2並不是很好的值。 其他2-4字節素數也很常見。

現在,如果您知道字節序,則可以看一下模數。 如果最高字節值為00則您正在處理模數的帶符號表示。 否則,它很可能是未簽名的。 包含位的模數的最高位字節應始終為80或更高。 原因是否則密鑰大小將小於給定的密鑰大小。 假設密鑰大小是8​​的倍數。

Java僅對BigInteger (以及任何其他數字表示形式)使用big endian。 因此,如果您使用C進行的字節序編碼很少,那么您需要反轉Java中的值。 最好反轉字符串中的十六進制值以完成此操作。 確保一次處理2個十六進制字符。

然后,按照DrYap的建議,使用BigInteger的十六進制構造函數。 請注意,如果最終使用字節數組,則可能要使用new BigInteger(1, MODULUS)因為這可以確保您獲得正數,而與編碼中的最高位無關。

暫無
暫無

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

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