2015-11-30 4 views
0

У меня есть мобильное приложение, написанное в Objective C (iOS), которое мне нужно для генерации подписей для проверки сервером с использованием открытого ключа, предоставленного ранее.Подписи OpenSSL не проверяются в Java

Я пытаюсь получить подписи для проверки, которые были созданы OpenSSL в моем мобильном приложении. У меня Java-связь Java работает и создает достоверные подписи, я просто не могу заставить OpenSSL создать те, которые действительны. Возможно, мой алгоритм Java неверен, но на этом этапе я довольно новичок в этом.

Вот мой OpenSSL код для генерации подписи:

RCT_EXPORT_METHOD(signDataWithKey:(NSString *)dataToSign 
        privateKey:(NSString *)privateKey 
        callback:(RCTResponseSenderBlock)callback) 
{ 
    int retEr; 
    char* text = (char*) [dataToSign UTF8String]; 
    unsigned char *data; 
    unsigned long dataLen; 

    // converting nsstring base64 private key to openssl RSA key 

    BIO *mem = NULL; 
    RSA *rsa_private = NULL; 
    char *private_key = (char*)[privateKey UTF8String]; 

    NSLog(@"Processing private key %s", private_key); 

    mem = BIO_new_mem_buf(private_key, strlen(private_key)); 
    if (mem == NULL) 
    { 
    char buffer[120]; 
    ERR_error_string(ERR_get_error(), buffer); 
    NSLog(@"Error loading private key %s", buffer); 
    } 

    rsa_private = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, NULL); 
    BIO_free (mem); 
    if (rsa_private == NULL) 
    { 
    char buffer[120]; 
    ERR_error_string(ERR_get_error(), buffer); 
    NSLog(@"OpenSSL error: %s", buffer); 
    } else { 
    NSLog(@"Successfully loaded private key"); 
    } 
    // end of convertion 

    data = (unsigned char *) text; 
    dataLen = strlen(text); 


    //// creating signature 
    // sha256 
    unsigned char hash[SHA256_DIGEST_LENGTH]; 
    unsigned char sign[256]; 
    unsigned int signLen; 



    SHA256(data, dataLen, hash); 

    unsigned char *shaString = sha256_hash_string(hash); 

    NSData* plainData = [NSData dataWithBytes:(const void *)shaString length:strlen(shaString)]; 
    NSString *base64String = [plainData base64EncodedStringWithOptions:0]; 

    NSLog(@"Base64 checksum %@", base64String); 

    NSLog(@"SHA256 of %s is %send", text, shaString); 


    // signing 
    retEr = RSA_sign(NID_sha256WithRSAEncryption, shaString, strlen(shaString), sign, &signLen, rsa_private); 
    NSData* signatureData = [NSData dataWithBytes:(const void *)sign length:signLen]; 
    NSString *base64Signature = [signatureData base64EncodedStringWithOptions:0]; 
    NSLog(@"Got signed data %@", base64Signature); 


    // printf("Signature len gth = %d\n", signLen); 
    NSLog(@"RSA_sign: %@ signature length = %u", (retEr == 1) ? @"RSA_sign success": @"RSA_sign error", signLen); 

    NSLog(@"Got signed data %@", base64Signature); 


    RSA_free(rsa_private); 
    callback(@[base64Signature]); 
} 

unsigned char *sha256_hash_string (unsigned char hash[SHA256_DIGEST_LENGTH]) 
{ 
    unsigned char *outputBuffer = calloc(65, sizeof(char)); 

    int i = 0; 

    for(i = 0; i < SHA256_DIGEST_LENGTH; i++) 
    { 
    sprintf(outputBuffer + (i * 2), "%02x", hash[i]); 
    } 

    outputBuffer[64] = 0; 

    return outputBuffer; 

} 

Вы увидите, что я на самом деле, используя строковое представление SHA256 хэш - не бинарное - это нарочно. Затем я беру эту строку и подписываю ее.

Теперь вот код Java для проверки подписи:

public static boolean verifySignature(PublicKey publicKey, byte[] signedData, String signature) { 
     java.security.Security.addProvider(
       new org.bouncycastle.jce.provider.BouncyCastleProvider() 
    ); 
     Signature signatureCheck = Signature.getInstance("SHA256withRSA", "BC"); 
     signatureCheck.initVerify(publicKey); 
     signatureCheck.update(signedData); 

     return signatureCheck.verify(CryptoUtil.Base64Decode(signature)) 
    } 

Все кажется правильным (я вручную подтверждено частный ключ/открытых ключей пары), и если я подпишу одни и те же данные с помощью Java это будет проверять (как следует):

public static String getSignatureForString(PrivateKey privateKey, String data) { 
     Signature signature = Signature.getInstance("SHA256withRSA", "BC"); 
     signature.initSign(privateKey); 

     signature.update(data.getBytes()); 

     byte[] signed = signature.sign(); 

     return CryptoUtil.Base64Encode(signed); 
    } 

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

+1

Вы говорите, что вы подписали шестнадцатеричную строку вместо фактического хэш «на цели», но вы также сделали это с нарушением стандарта (RSASSA-PKCS1-v1_5 обычно называют просто PKCS1) и, таким образом, получаете значение подписи это неправильно и не будет проверяться. И правильным OID в кодировке для этого стандарта является хэш-алгоритм (здесь SHA256 2.16.840.1.101.3.4.2.1), а не схема подписи (SHA256withRSA 1.2.840.113549.1.1.11). –

+0

Спасибо @ dave_thompson_085 за это - я не уверен, что понимаю нарушение - данные - это то, что - данные - не сам собственно сигнатур/алгоритм. Как я уже говорил, я совершенно новичок в этом вопросе - есть ли у вас какие-либо предложения по решению этой проблемы? –

+0

@ dave_thompson_085 - понял (ответ отправлен), хотя я все еще подписываю пользовательский хеш. Не знаю, почему это неправильно, но дайте мне знать, если сможете. –

ответ

0

ОК, поэтому я точно не знаю, почему это ничем не отличается от метода RSA_sign, но после тестирования openssl_verify() и openssl_sign() в PHP, и эти функции дают правильные результаты для подписей, созданных на Java. Я решил прочитайте исходный код PHP, чтобы выяснить, как они это делают. В любом случае PHP использует функции с префиксом EVP_ (высокоуровневые криптографические функции в соответствии с документацией OpenSSL). Во всяком случае, я скорректировал код Objective C, чтобы вместо этого использовать эти функции, и теперь мои подписи соответствуют всем языкам. Я надеюсь, что это помогает кому-то.

RCT_EXPORT_METHOD(signDataWithKey:(NSString *)dataToSign 
        privateKey:(NSString *)privateKey 
        callback:(RCTResponseSenderBlock)callback) 
{ 
    int retEr; 
    char* text = (char*) [dataToSign UTF8String]; 
    unsigned char *data; 
    unsigned long dataLen; 

    // converting nsstring base64 private key to openssl RSA key 

    BIO *mem = NULL; 
    EVP_PKEY *pkey; 
    char *private_key = (char*)[privateKey UTF8String]; 

    EVP_MD_CTX md_ctx; 

    NSLog(@"Processing private key %s", private_key); 


    mem = BIO_new_mem_buf(private_key, strlen(private_key)); 
    if (mem == NULL) 
    { 
    char buffer[120]; 
    ERR_error_string(ERR_get_error(), buffer); 
    NSLog(@"Error loading private key %s", buffer); 
    } 

    // CHANGED 
    pkey = PEM_read_bio_PrivateKey(mem, NULL, NULL, NULL); 

    BIO_free (mem); 
    if (pkey == NULL) 
    { 
    char buffer[120]; 
    ERR_error_string(ERR_get_error(), buffer); 
    NSLog(@"OpenSSL error: %s", buffer); 
    } else { 
    NSLog(@"Successfully loaded private key"); 
    } 
    // end of convertion 

    data = (unsigned char *) text; 
    dataLen = strlen(text); 


    //// creating signature 
    // sha256 
    unsigned char hash[SHA256_DIGEST_LENGTH]; 
    unsigned char sign[4096]; 
    int signLen; 



    SHA256(data, dataLen, hash); 

    unsigned char *shaString = sha256_hash_string(hash); 

    NSData* plainData = [NSData dataWithBytes:(const void *)shaString length:strlen(shaString)]; 
    NSString *base64String = [plainData base64EncodedStringWithOptions:0]; 

    NSLog(@"Base64 checksum %@", base64String); 

    NSLog(@"SHA256 of %s is %s end", text, shaString); 

    // CHANGED - Using EVP to sign now. 
    EVP_SignInit(&md_ctx, EVP_sha256()); 
    EVP_SignUpdate(&md_ctx, shaString, strlen(shaString)); 
    retEr = EVP_SignFinal(&md_ctx, sign, &signLen, pkey); 


    // OLD METHOD 
    //retEr = RSA_sign(NID_sha256WithRSAEncryption, shaString, strlen(shaString), sign, &signLen, rsa_private); 


    NSData* signatureData = [NSData dataWithBytes:(const void *)sign length:signLen]; 
    NSString *base64Signature = [signatureData base64EncodedStringWithOptions:0]; 
    NSLog(@"Got signed data %@", base64Signature); 


    // printf("Signature len gth = %d\n", signLen); 
    NSLog(@"RSA_sign: %@ signature length = %u", (retEr == 1) ? @"RSA_sign success": @"RSA_sign error", signLen); 

    NSLog(@"Got signed data %@", base64Signature); 


    EVP_PKEY_free(pkey); 
    callback(@[base64Signature]); 
} 

unsigned char *sha256_hash_string (unsigned char hash[SHA256_DIGEST_LENGTH]) 
{ 
    unsigned char *outputBuffer = calloc(65, sizeof(char)); 

    int i = 0; 

    for(i = 0; i < SHA256_DIGEST_LENGTH; i++) 
    { 
    sprintf(outputBuffer + (i * 2), "%02x", hash[i]); 
    } 

    outputBuffer[64] = 0; 

    return outputBuffer; 

} 
Смежные вопросы