2014-01-09 3 views
2

В моем приложении у меня есть открытый ключ (представленный как строка), простое сообщение и цифровую подпись, представленную как закодированная в base64 строка, хэшированная с SHA256 и зашифрованная с помощью RSA). Теперь мне нужно проверить цифровую подпись. Я пытался сделать следующим образом:iOS проверить цифровую подпись

  1. создать SecKeyRef из NSString (взято из here)
  2. создают дайджеста SHA256 из исходного сообщения
  3. проверки подписи с помощью SecKeyRawVerify функции

(я пытаюсь чтобы избежать использования функции OpenSSL)

Кроме того, моя цифровая подпись была создана нами используя метод SHA256withRSA Java. Я читал here, что SHA256WithRSA добавляет идентификатор алгоритма с фактическим хешем. Теперь я не уверен, нужно ли добавлять его к хешу.

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

Вот мой код:

-(BOOL) verifySignature:(NSString*) rawData andKey:(NSString*) key andSignature:(NSString*)signature { 

    NSData* originalData = [rawData dataUsingEncoding:NSUTF8StringEncoding]; 
    NSData *signatureData = [NSData dataFromBase64String:signature]; 

    SecKeyRef publicKey = [self generatePublicKey:key]; 

    uint8_t sha2HashDigest[CC_SHA256_DIGEST_LENGTH]; 
    CC_SHA256([originalData bytes], [originalData length], sha2HashDigest); 

    //DO I NEED THIS? 
    NSString *algIdentifier = @"1.3.14.3.2.26"; 
    NSData *algData = [algIdentifier dataUsingEncoding:NSUTF8StringEncoding]; 
    NSData* d_hash = [NSData dataWithBytes:sha2HashDigest length:CC_SHA256_DIGEST_LENGTH]; 

    NSMutableData *concatenatedData = [NSMutableData data]; 
    [concatenatedData appendData:algData]; 
    [concatenatedData appendData:d_hash]; 

    OSStatus verficationResult = SecKeyRawVerify (publicKey, 
        kSecPaddingPKCS1SHA256, 
        (const uint8_t *)[d_hash bytes], 
        (size_t)[d_hash length], 
        (const uint8_t *)[signatureData bytes], 
        (size_t)[signatureData length] 
        ); 


    CFRelease(publicKey); 

    if (verficationResult == errSecSuccess){ 
     NSLog(@"Verified"); 
     return YES; 
    } 
    return NO; 

} 

- (SecKeyRef)generatePublicKey:(NSString *)key 
{ 

    // This will be base64 encoded, decode it. 
    NSData *d_key = [NSData dataFromBase64String:key]; 
    d_key = [self stripPublicKeyHeader:d_key]; 
    if (d_key == nil) return(nil); 

    NSData *d_tag = [NSData dataWithBytes:[@"pubKey" UTF8String] length:[@"pubKey" length]]; 

    NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; 
    [publicKey setObject:(id) kSecClassKey forKey:(id)kSecClass]; 
    [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 
    [publicKey setObject:d_tag forKey:(id)kSecAttrApplicationTag]; 
    SecItemDelete((CFDictionaryRef)publicKey); 

    CFTypeRef persistKey = nil; 

    // Add persistent version of the key to system keychain 
    [publicKey setObject:d_key forKey:(id)kSecValueData]; 
    [publicKey setObject:(id) kSecAttrKeyClassPublic forKey:(id) 
    kSecAttrKeyClass]; 
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id) 
    kSecReturnPersistentRef]; 

    OSStatus secStatus = SecItemAdd((CFDictionaryRef)publicKey, &persistKey); 
    if (persistKey != nil) CFRelease(persistKey); 

    if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) { 
     [publicKey release]; 
     return(nil); 
    } 

    // Now fetch the SecKeyRef version of the key 
    SecKeyRef keyRef = nil; 

    [publicKey removeObjectForKey:(id)kSecValueData]; 
    [publicKey removeObjectForKey:(id)kSecReturnPersistentRef]; 
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef 
    ]; 

    [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 
    secStatus = SecItemCopyMatching((CFDictionaryRef)publicKey, 
            (CFTypeRef *)&keyRef); 

    [publicKey release]; 
    return keyRef; 

} 

ответ

3

Возможно, этот ответ немного поздно, но у меня была та же проблема.

Оказывается, Java обрабатывает хеширование для вас, но iOS этого не делает.

Так что если у вас есть открытый текст под названием plainText вы могли бы генерировать подпись на нем в Java делает это:

public static byte[] sign(PrivateKey key, byte[] plainText) { 
    try { 
     Signature signature = Signature.getInstance("SHA256withRSA"); 
     signature.initSign(key); 
     signature.update(plainText); 
     return signature.sign(); 
    } catch (Exception e) { 
     return null; 
    } 
} 

Но затем проверить его в прошивкой вам нужно вручную сделать хэш открытого текста, как так :

+ (BOOL)verifySignature:(uint8_t*)signature signatureLen:(size_t)sLen 
      withPlainText:(uint8_t*)plainText plainTextLen:(size_t)pLen 
      andKey:(SecKeyRef)key { 
    uint8_t hash[32]; 
    CC_SHA256(plainText, pLen, hash); 
    OSStatus returnCode = SecKeyRawVerify(key, 
              kSecPaddingPKCS1SHA256, 
              hash, 
              32, 
              signature, 
              sLen); 
    return returnCode == 0; 
} 

В описанном выше способе, signature это байты, генерируемые с помощью метода Java.

Конечно, вы можете не захотеть жестко задавать такие параметры, как используемая функция хэша (и длина хэша).

+0

Перед вызовом SecKeyRawVerify вам необходимо предварительно присвоить идентификатор алгоритма вашему массиву «hash», полученному с помощью CC_SHA256 – Maggie

+0

Хмм, я не вижу, где это указано в документации. В этом аргументе говорится: «данные, по которым проверяется [подпись], обычно дайджест фактических данных», и поэтому я передал дайджест фактических данных (хэш SHA256). Не могли бы вы уточнить? Какой именно формат? – user3100783

+0

Просто передал данные для вас? Мне пришлось добавить идентификатор алгоритма к фактическим хэшированным данным. id-sha256: 30 0b 06 09 60 86 48 01 65 03 04 02 01 – Maggie

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