2016-11-10 33 views
0

我試圖在iOS上使用橢圓曲線算法簽名數據並驗證簽名。創建密鑰工作得很好,但試圖簽署數據返回錯誤-1 - 這是非常通用的。在iOS上使用kSecAttrKeyTypeEC鍵簽名數據

的鍵創建如下:

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

這將返回狀態0,到目前爲止,一切順利。實際簽約情況是這樣的:

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

的調用SecKeyRawSign()回報-1

這是從https://forums.developer.apple.com/message/95740#95740

什麼是用於簽名數據的EC鍵選擇正確的方式適應?這裏有一個RSA密鑰的工作解決方案:Signing and Verifying on iOS using RSA但我無法將它適配到EC密鑰。

回答

1

似乎是創建指針並計算調用SecKeyRawSign時數據大小的正確語法的一部分。在斯威夫特3工作示例如下:

生成密鑰,存儲在安全區域(和暫時的實例變量):

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 
} 

註冊數據

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) 
} 

驗證簽名

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 
} 

如果需要出口公鑰,以便它可以被其他應用程序或設備一起使用,這可以這樣進行:

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)") 
}