0

我在 ObjectiveC 中签署一个字符串并在 PHP 中验证生成的签名。

假设我在ObjectiveC中使用我的privateKey和RSA_sign方法(OpenSSL Lib)签署了一个字符串“b1be1970fa802f43cdfa382bb3f3a524590b2170”。我得到生成的签名

我使用带有 openssl_verify 方法的 PublicKey 验证 PHP 中的签名。

验证失败

知道可能出了什么问题..

iOS 代码:

NSString *handshakeChallengeStr = [NSString stringWithFormat:@"YjFiZTE5NzBmYTgwMmY0M2NkZmEzODJiYjNmM2E1MjQ1OTBiMjE3MA=="];
NSData *hcData = [NSData dataFromBase64String:handshakeChallengeStr];
const unsigned char *message = (const unsigned char *)[hcData bytes];
unsigned int message_length =strlen((const void *)message); //56

unsigned char *sig = NULL;
unsigned int sig_len = 0;

//Retriving PrivateKey
RSA *privKey = NULL;
EVP_PKEY *PrivateKey;
FILE *priv_key_file;
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString *keyFilePath = [[paths objectAtIndex:0]stringByAppendingPathComponent:@"privateKey.pem"];

priv_key_file = fopen([keyFilePath UTF8String], "r");
PrivateKey = PEM_read_PrivateKey(priv_key_file, NULL, NULL, NULL);
privKey = EVP_PKEY_get1_RSA(PrivateKey);

sig = malloc(RSA_size(privKey));

int success = RSA_sign(NID_sha1, message, message_length, sig, &sig_len, privKey);
if(success == 1){
    NSLog(@"Signature Generated!!");
}

PHP代码:

$private = '-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDZz+ztvFV3qYu8
4NHErDVfVzfVhAVoCqQiCFBWpuNJk0xPgGIkwDkehhyIxCT1CD/GNYQSjpoFlfId
….
-----END PRIVATE KEY-----';

$public='-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2c/s7bxVd6mLvODRxKw1
X1c31YQFaAqkIghQVqbjSZNMT4BiJMA5HoYciMQk9Qg/xjWEEo6aBZXyHekc7w1d
……
-----END PUBLIC KEY-----';

$HandshakeStr = base64_decode('YjFiZTE5NzBmYTgwMmY0M2NkZmEzODJiYjNmM2E1MjQ1OTBiMjE3MA==');;

openssl_sign($HandshakeStr, $sig, $private);
4

2 回答 2

2

PHP通过使用 SHA1 进行散列PHP:openssl_signopenssl_sign计算指定数据的签名。

OpenSSL RSA_sign对大小为 m_len的消息摘要m 进行签名 ( OpenSSL: RSA_sign(3) )

当您使用原始 OpenSSL 函数时,您必须自己进行散列:

    unsigned char message_digest[SHA_DIGEST_LENGTH];
    SHA1(message, message_length, message_digest);
    int success = RSA_sign(NID_sha1, message_digest, SHA_DIGEST_LENGTH, sig, &sig_len, privKey);

顺便说一句,使用 RSA 验证 - 并非每个签名方案都是确定性的。

于 2013-08-28T14:28:01.230 回答
1

我认为您应该检查以下行

unsigned int message_length =strlen((const void *)message);

由于消息是二进制的(它是从 Base64 解码的,并且可以在两者之间包含 NULL 字符),strlen 不会返回正确的长度。您应该从 NSData 获取消息中的确切字节数。

根据我的计算,长度不应该是 56,而是 42 左右。由于 Base64 中 3 位占用 4 位,因此 56*3/4 为 42。

在这里,您的目的是获取 base64 解码字节的长度。您可以使用

message_length = [hcData length];

在对数据进行签名和验证之前,请检查数据是否正确解码。

另一个原因 在深入研究之前,让我们先分析一下什么会导致签名生成和验证成功。

签名生成涉及:

  1. 私钥
  2. 数据
  3. 哈希算法

它生成一个签名。

和验证需要:

  1. 公钥
  2. 数据
  3. 哈希算法
  4. 签名

公钥应与私钥匹配。否则,签名验证不会成功。

数据必须相同。每一点都应该是一样的。

签名和验证中使用的哈希算法必须相同。

之后,签名中生成的签名应该与验证中使用的签名相同。

任何不匹配都会导致签名不匹配。

我相信这可能会帮助您找出问题所在。

于 2013-08-25T05:23:33.913 回答