2

所以,我使用了一个专有库,它有自己的实现来创建 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
4

2 回答 2

2

我假设您不能只发送二进制数据,因为您提到了十六进制转换。以文本形式发送数据的最紧凑方式是使用 base 64,但这比十六进制更复杂。

客户端

使用您拥有的链接中的方法将 unsigned char 数组转换为十六进制字符串。该bits字段将确定要使用数组中的多少字节,由 给出(bits+7)/8

根据实现,您可能必须显式选择溢出位,否则其余位可能会被清零,这也取决于字节顺序,因此由于您不确定实现细节,您可能不得不稍微摆弄一下。

获得编码字符串后,将它们发送到服务器。

服务器端

从连接中读取编码字符串,然后BigInteger(String val, int radix)使用十六进制 (16) 的基数将它们传递给构造函数。

然后,您将获得BigInteger具有所需值的 A。

于 2013-08-09T21:50:10.827 回答
1

如果公共指数的第一个字节全为零,那么您正在处理一个大端数组。这是最常见的。原则上,公共指数可以与模数一样大,但通常情况并非如此。最常见的值是 65537、17 和 3,甚至可能是 2,但 3 和 2 并不是很好的值。其他 2-4 字节素数也很常见。

现在如果你知道字节序,你可以看看模数。如果最高字节值是,00那么您正在处理模数的有符号表示。否则很可能是未签名的。包含位的模数的最高位字节应始终为80或更高。原因是否则密钥大小将小于给定的密钥大小。这是假设密钥大小当然是 8 的倍数。

Java 仅适用于大端BigInteger(以及任何其他数字表示)。因此,如果您在 C 中使用小端编码,那么您需要反转 Java 中的值。最好反转字符串中的十六进制值来实现这一点。确保一次处理 2 个十六进制字符。

然后,正如 DrYap 建议的那样,使用BigInteger. 请注意,如果您最终使用字节数组,那么您可能希望使用new BigInteger(1, MODULUS)它,因为这可以确保您获得一个正数,而不管编码中的最高位值如何。

于 2013-08-10T00:26:51.477 回答