PHP openssl_sign генерирует другую подпись, чем знак SSCrypto - PullRequest
3 голосов
/ 23 апреля 2010

Я пишу OS X-клиент для программного обеспечения, написанного на PHP. Это программное обеспечение использует простой интерфейс RPC для получения и выполнения команд. RPC-клиент должен подписывать отправляемые им команды, чтобы ни один MITM не мог изменить ни одну из них.

Однако, поскольку сервер не принимал подписи, которые я отправил от своего клиента OS X, я начал исследовать и обнаружил, что функция openssl_sign PHP генерирует подпись для данной комбинации секретного ключа / данных, отличную от Objective-C * 1003. * SSCrypto framework (который является только оболочкой для 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+ ... (Для моего определенного ключа, конечно. Закодировано base64)

Я не совсем уверен, почему это происходит, и я безуспешно экспериментировал с различными хэш-алгоритмами. Как указано в документации PHP, по умолчанию используется SHA1.

Так почему же эти две функции генерируют разные сигнатуры и как я могу заставить свою часть Objective C генерировать сигнатуру, которую примет PHP openssl_verify?

Примечание: я дважды проверил, что ключи и данные верны!

Ответы [ 4 ]

8 голосов
/ 25 апреля 2010

Хорошо, прошло довольно много часов.Вот что происходит:

Когда вы вызываете функцию openssl_sign, PHP внутренне использует API-интерфейс EVP, предоставляемый openssl lib.EVP - это высокоуровневый API для базовых функций, таких как RSA_private_encrypt.Поэтому, когда вы вызываете base64_encode(openssl_sign('hello', $signature, $privKey)), это похоже на выполнение чего-то подобного в командной строке с использованием двоичного файла openssl:

echo -n "hello"| openssl dgst -sha1 -sign priv.key | openssl enc -base64

и NOT

echo -n "hello" | openssl dgst -sha1 | openssl rsautl -encrypt priv.key | openssl enc -base64

Iне знаю, почему это дает разные результаты, но это так.Если у кого-то есть идея, почему они отличаются: пожалуйста, поделитесь!
Однако, поскольку я использую инфраструктуру SSCrypto, я переписал функцию -sign (и -verify) с вызовами EVP (аннотация):

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.

Спасибо вам, ребята, за то, что направили меня в правильном направлении!

2 голосов
/ 22 ноября 2011

Ваш фрагмент кода очень помог, у меня была та же проблема, и я предложил следующий метод, основанный на ваших строках, если это поможет кому-то с такой же проблемой.

- (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;

}

0 голосов
/ 31 июля 2010

Не то, что это исправляет, но ваше использование rsautl кажется неправильным.Вы, вероятно, должны использовать rsautl -sign вместо rsautl -encrypt

0 голосов
/ 24 апреля 2010

Мне кажется, что ваш PHP подписывает "hello", а ваш Objective-C подписывает sha1("hello").То есть, как я читаю документы, PHP openssl_sign использует sha1 по умолчанию во внутренней механике подписи, в отличие от применения sha1 к данным перед подписью.

...