2016-11-10 1 views
0

Je tente de signer des données et de vérifier la signature à l'aide de l'algorithme Elliptic Curve sur iOS. La création des clés fonctionne assez bien, mais tenter de signer les données renvoie l'erreur -1 - ce qui est très générique.Signature des données avec la clé kSecAttrKeyTypeEC sur iOS

Les clés sont créées comme suit:

publicKeyRef = NULL; 
privateKeyRef = NULL; 

NSDictionary * privateKeyAttr = @{(id)kSecAttrIsPermanent : @1, 
            (id)kSecAttrApplicationTag : privateTag}; 

NSDictionary * publicKeyAttr = @{(id)kSecAttrIsPermanent : @1, 
           (id)kSecAttrApplicationTag : privateTag}; 

NSDictionary * keyPairAttr = @{(id)kSecAttrKeySizeInBits : @(keySize), 
           (id)kSecAttrKeyType : (id)kSecAttrKeyTypeEC, 
           (id)kSecPrivateKeyAttrs : privateKeyAttr, 
           (id)kSecPublicKeyAttrs : publicKeyAttr}; 

OSStatus status = SecKeyGeneratePair((CFDictionaryRef)keyPairAttr, &publicKeyRef, &privateKeyRef); 

Ce statut renvoie 0, jusqu'à présent si bon. La signature réelle se présente comme suit:

- (NSData *) signData:(NSData *)dataToSign withPrivateKey:(SecKeyRef)privateKey { 
    NSData * digestToSign = [self sha1DigestForData:dataToSign]; 

    size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey); 

    uint8_t * signedHashBytes = malloc(signedHashBytesSize * sizeof(uint8_t)); 
    memset((void *)signedHashBytes, 0x0, signedHashBytesSize); 
    OSStatus signErr = SecKeyRawSign(privateKey, 
           kSecPaddingPKCS1, 
           digestToSign.bytes, 
           digestToSign.length, 
           (uint8_t *)signedHashBytes, 
           &signedHashBytesSize); 
    NSLog(@"Status: %d", signErr); 

    NSData * signedHash = [NSData dataWithBytes:(const void *)signedHashBytes length:(NSUInteger)signedHashBytesSize]; 
    if (signedHashBytes) free(signedHashBytes); 

    return (signErr == noErr) ? signedHash : nil; 
} 

- (NSData *)sha1DigestForData:(NSData *)data { 
    NSMutableData *result = [[NSMutableData alloc] initWithLength:CC_SHA1_DIGEST_LENGTH]; 
    CC_SHA1(data.bytes, (CC_LONG) data.length, result.mutableBytes); 

    return result; 
} 

L'appel à SecKeyRawSign() retours -1.

C'est adapté de https://forums.developer.apple.com/message/95740#95740

Quelle est la bonne façon d'utiliser une clé CE pour les données de signature? Il y a une solution de travail pour les clés RSA ici: Signing and Verifying on iOS using RSA mais je n'ai pas pu l'adapter aux clés EC.

Répondre

1

On dirait qu'une partie du problème est avec la syntaxe correcte lors de la création des pointeurs et le calcul de la taille des données pour les appels à SecKeyRawSign. Un exemple de travail dans Swift 3 ressemble à ceci:

générer des clés, stockées dans l'Enclave (Secure et temporairement dans les variables d'instance):

func generateKeyPair() -> Bool { 
    if let access = SecAccessControlCreateWithFlags(nil, 
                kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, 
                [.userPresence, .privateKeyUsage], 
                nil) { 

     let privateKeyAttr = [kSecAttrIsPermanent : 1, 
           kSecAttrApplicationTag : privateTag, 
           kSecAttrAccessControl as String: access 
      ] as NSDictionary 

     let publicKeyAttr = [kSecAttrIsPermanent : 0, 
          kSecAttrApplicationTag : publicTag 
      ] as NSDictionary 

     let keyPairAttr = [kSecAttrKeySizeInBits : 256, 
          kSecAttrKeyType : kSecAttrKeyTypeEC, 
          kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, 
          kSecPrivateKeyAttrs : privateKeyAttr, 
          kSecPublicKeyAttrs : publicKeyAttr] as NSDictionary 

     let err = SecKeyGeneratePair(keyPairAttr, &publicKey, &privateKey) 
     return err == noErr 
} 

données Signe:

func signData(plainText: Data) -> NSData? { 
    guard privateKey != nil else { 
     print("Private key unavailable") 
     return nil 
    } 

    let digestToSign = self.sha1DigestForData(data: plainText as NSData) as Data 

    let signature = UnsafeMutablePointer<UInt8>.allocate(capacity: 128) 
    var signatureLength = 128 
    let err = SecKeyRawSign(privateKey!, 
          .PKCS1SHA1, 
          [UInt8](digestToSign), 
          Int(CC_SHA1_DIGEST_LENGTH), 
          signature, 
          &signatureLength) 

    print("Signature status: \(err)") 

    let sigData = NSData(bytes: signature, length: Int(signatureLength)) 

    return sigData 
} 

func sha1DigestForData(data: NSData) -> NSData { 
    let len = Int(CC_SHA1_DIGEST_LENGTH) 
    let digest = UnsafeMutablePointer<UInt8>.allocate(capacity: len) 
    CC_SHA1(data.bytes, CC_LONG(data.length), digest) 
    return NSData(bytesNoCopy: UnsafeMutableRawPointer(digest), length: len) 
} 

Vérifier la signature:

func verifySignature(plainText: Data, signature: NSData) -> Bool { 
    guard publicKey != nil else { 
     print("Public key unavailable") 
     return false 
    } 

    let digestToSign = self.sha1DigestForData(data: plainText as NSData) as Data 
    let signedHashBytesSize = signature.length 

    let err = SecKeyRawVerify(publicKey!, 
           .PKCS1SHA1, 
           [UInt8](digestToSign), 
           Int(CC_SHA1_DIGEST_LENGTH), 
           [UInt8](signature as Data), 
           signedHashBytesSize) 

    print("Verification status: \(err)") 

    return err == noErr 
} 

Si vous devez exporter la clé publique afin qu'il puisse être utilisé par une autre application ou un appareil, cela peut être fait comme ceci:

let parameters = [ 
    kSecClass as String: kSecClassKey, 
    kSecAttrKeyType as String: kSecAttrKeyTypeEC, 
    kSecAttrLabel as String: "Public Key", 
    kSecAttrIsPermanent as String: false, 
    kSecValueRef as String: publicKey, 
    kSecAttrKeyClass as String: kSecAttrKeyClassPublic, 
    kSecReturnData as String: true 
    ] as CFDictionary 
var data:AnyObject? 
let status = SecItemAdd(parameters, &data) 
print("Public key added \(status)") 
if let keyData = data as? NSData { 
    print("This is the key, send it where it needs to go:\n\(keyData)") 
}