2016-11-10 4 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.

서명 데이터에 대한 EC의 키를 사용하는 올바른 방법이 무엇 https://forums.developer.apple.com/message/95740#95740 각색? 여기에 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)") 
} 
관련 문제