![](/img/trans.png)
[英]Signature for CloudFront Signed URL differs when using openssl sha1 -sign and PHP's openssl_sign
[英]PHP's openssl_sign generates different signature than SSCrypto's sign
我正在為一個用PHP編寫的軟件編寫OS X客戶端。 該軟件使用簡單的RPC接口來接收和執行命令。 RPC客戶端必須對他發送的命令進行簽名,以確保沒有MITM可以修改它們中的任何一個。
但是,由於服務器不接受我從OS X客戶端發送的簽名,我開始調查並發現PHP的openssl_sign函數為給定的私鑰/數據組合生成與Objective-C SSCrypto框架不同的簽名(這是只是openssl lib的包裝器:
SSCrypto *crypto = [[SSCrypto alloc] initWithPrivateKey:self.localPrivKey];
NSData *shaed = [self sha1:@"hello"];
[crypto setClearTextWithData:shaed];
NSData *data = [crypto sign];
生成像CtbkSxvqNZ+mAN
這樣的簽名......
PHP代碼
openssl_sign("hello", $signature, $privateKey);
生成一個像6u0d2qjFiMbZ+
...的簽名(對於我的某些鍵,當然6u0d2qjFiMbZ+
編碼)
我不太清楚為什么會發生這種情況而且我沒有成功地嘗試使用不同的哈希算法。 由於PHP文檔聲明默認使用SHA1。
那么為什么這兩個函數會生成不同的簽名?如何讓Objective-C部分生成PHP openssl_verify接受的簽名?
注意:我仔細檢查了密鑰和數據是否正確!
好的,花了不少時間。 這是發生了什么:
當您調用openssl_sign
函數時,PHP在內部使用openssl lib提供的EVP API。 EVP是RSA_private_encrypt
等底層函數的“高級”API。 因此,當您調用base64_encode(openssl_sign('hello', $signature, $privKey))
,使用openssl二進制文件在命令行上執行類似的操作:
echo -n "hello"| openssl dgst -sha1 -sign priv.key | openssl enc -base64
而不是
echo -n "hello" | openssl dgst -sha1 | openssl rsautl -encrypt priv.key | openssl enc -base64
我不知道為什么會產生不同的輸出,但確實如此。 如果有人知道他們為什么不同:請分享!
但是,當我使用SSCrypto框架時,我用EVP調用重寫了-sign(和-verify)函數(abstract):
OpenSSL_add_all_digests();
EVP_MD_CTX_init(&md_ctx);
EVP_SignInit(&md_ctx, mdtype);
EVP_SignUpdate(&md_ctx, input, inlen);
if (EVP_SignFinal(&md_ctx, (unsigned char*) outbuf, (unsigned int *)&outlen, pkey)) {
NSLog(@"signed successfully.");
}
瞧:我得到了與PHP相同的簽名。 哦,為了記錄:PHP使用PKCS填充。
謝謝你們指點我正確的方向!
你的代碼片段是一個很大的幫助,我有同樣的問題,我想出了基於你的行的以下方法,如果這有助於任何人有同樣的問題。
- (NSData *)getSignature {
NSString * signString = [self getSignatureText];
NSData * privateKeyData = [self getPrivateKey];
BIO *publicBIO = NULL;
EVP_PKEY *privateKey = NULL;
if (!(publicBIO = BIO_new_mem_buf((unsigned char *)[privateKeyData bytes], [privateKeyData length]))) {
NSLog(@"BIO_new_mem_buf() failed!");
return nil;
}
if (!PEM_read_bio_PrivateKey(publicBIO, &privateKey, NULL, NULL)) {
NSLog(@"PEM_read_bio_PrivateKey() failed!");
return nil;
}
const char * data = [signString cStringUsingEncoding:NSUTF8StringEncoding];
unsigned int length = [signString length];
int outlen;
unsigned char * outbuf[EVP_MAX_MD_SIZE];
const EVP_MD * digest = EVP_md5();
EVP_MD_CTX md_ctx;
EVP_MD_CTX_init(&md_ctx);
EVP_SignInit(&md_ctx, digest);
EVP_SignUpdate(&md_ctx, data, length);
if (EVP_SignFinal(&md_ctx, (unsigned char*) outbuf, (unsigned int *) &outlen, privateKey)) {
NSLog(@"Signed successfully.");
}
EVP_MD_CTX_cleanup(&md_ctx);
EVP_PKEY_free(privateKey);
NSData * signature = [NSData dataWithBytes:outbuf length:outlen];
return signature;
}
它看起來像你的PHP正在簽署"hello"
,而你的Objective-C正在簽署sha1("hello")
。 也就是說,我閱讀文檔的方式,PHP的openssl_sign
在簽名的內部機制中默認使用sha1
,而不是在簽名之前將sha1
應用於數據。
不是它修復,但你使用rsautl似乎是不正確的。 您可能應該使用rsautl -sign而不是rsautl -encrypt
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.