Closed hfossli closed 7 years ago
Example
func verify(signature: String, input: String, publicKey: SecKey) -> Bool {
????
}
let input = "aaa"
let signature = "MEQCIDupp6WmfmLPEOrd1xEgAP6wX7Qkpsi7eRUKumw2sJ3AAiAL5YGzuWFWD2FrjLCwuLKx4den9C2ZdpnhzxLVLauqcw=="
let publicKey = "BMD7LUJ/1DqB90hoASaTSEU1mcAI80O6XxOg8z2GqzJXJDSd7k/N9LjVl74EV2L77gmgFOTTXqT5ULvCdxtAnu8="
let valid = verify(signature: signature, publicKey: createKeyRef(publicKey), input: input)
Allright, I'm able to
@available(iOS 10.0, *)
func createPublicKey(from string: String) throws -> SecureEnclaveKeyReference {
let params: [String: Any] = [
kSecAttrKeyType as String: attrKeyTypeEllipticCurve,
kSecAttrKeySizeInBits as String: 256,
kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
]
let data = Data(base64Encoded: string)! as CFData
var error: Unmanaged<CFError>? = nil
guard let key = SecKeyCreateWithData(data, params as CFDictionary, &error) else {
throw SecureEnclaveHelperError(message: "bad", osStatus: 0)
}
return SecureEnclaveKeyReference(key)
}
I'll open a pull request on this in near future
@withzombies do you know how I can do the reverse of what's key_builder.rb
is doing?
I think you need to use SecCertificateCreateWithData
on the base64 decoded public key. Then use SecCertificateCopyPublicKey
to extract the public key as a SecKey
. Then you can use the SecKeyRawVerify
function.
Awesome! I'll try that tomorrow.
I think I managed to import the key at some point, but I found it easier to just verify the signature with openssl CLI. E.g.
/usr/local/opt/openssl/bin/openssl dgst -sha256 -verify key.pem -signature signature.dat dataToSign.dat
Hi @hfossli I am currently struggling with verify a signature generated in security framework with openssl. Good you to know you're able to verify the signature in openssl.
Do you have any pointers that could help?
Yep! I have some unpublished code for that! I'll try to publish this on a branch today.
Can you btw share your failing code example?
I don't know what issue you are facing.
Maybe you find one of these helpful
I recently encountered some issues with signatures and you may want to export them in a another binary format –for that issue have a look at EllipticCurveKeyPair.swift:388
in the zip file
// https://crypto.stackexchange.com/a/1797
// FIXME: R and S encoding issues https://github.com/IBM-Swift/BlueECC/blob/2c4ea97307b28c1338689b4f7a4391a14c0610a4/Sources/CryptorECC/ECSignature.swift#L120
static func encodeAsn1(_ bytes: Data) -> Data {
let (r, s) = split(bytes)
var asn1 = Data()
asn1.append(0x30)
asn1.append(UInt8(2 + r.count + 2 + s.count))
asn1.append(0x02)
asn1.append(UInt8(r.count))
asn1.append(r)
asn1.append(0x02)
asn1.append(UInt8(s.count))
asn1.append(s)
return asn1
}
sure...
here's the part that does the signing:
let privateKey: SecKey = retrieveKey(SCK_TAG)
let algorithm: SecKeyAlgorithm = .ecdsaSignatureMessageX962SHA256
guard SecKeyIsAlgorithmSupported(privateKey, .sign, algorithm) else {
fatalError("signing algorithm not supported")
}
let dataToSign = sadJson.data(using: .utf8)
var error: Unmanaged<CFError>?
guard let signature = SecKeyCreateSignature(privateKey, algorithm, dataToSign! as CFData, &error) as Data? else {
return ""
}
return signature.base64EncodedString()
The signature generated fails when verifying with openssl using:
openssl dgst -sha256 -verify pubkey.pem -signature sig.bin ssasad.bin
but this signature verifies OK when used with:
SecKeyVerifySignature(pubKey!, algorithm, dataToSign! as CFData, signature as CFData, nil)
Either the exported public key is in a bad format or the signature is in a bad format or both.
How do you export the public key?
this is how the key is exported:
func exportECPublicKeyToPEM(_ rawPublicKeyBytes: Data, keyType: String, keySize: Int) -> String {
return PEMKeyFromDERKey(exportECPublicKeyToDER(rawPublicKeyBytes, keyType: keyType, keySize: keySize))
}
/**
* This method transforms a DER encoded key to PEM format. It gets a Base64 representation of
* the key and then splits this base64 string in 64 character chunks. Then it wraps it in
* BEGIN and END key tags.
*/
func PEMKeyFromDERKey(_ data: Data) -> String {
// base64 encode the result
let base64EncodedString = data.base64EncodedString(options: [])
// split in lines of 64 characters.
var currentLine = ""
var resultString = kCryptoExportImportManagerPublicKeyInitialTag
var charCount = 0
for character in base64EncodedString {
charCount += 1
currentLine.append(character)
if charCount == kCryptoExportImportManagerPublicNumberOfCharactersInALine {
resultString += currentLine + "\n"
charCount = 0
currentLine = ""
}
}
// final line (if any)
if currentLine.count > 0 { resultString += currentLine + "\n" }
// final tag
resultString += kCryptoExportImportManagerPublicKeyFinalTag
return resultString
}
func exportECPublicKeyToDER(_ rawPublicKeyBytes: Data, keyType: String, keySize: Int) -> Data {
print("Exporting EC raw key: \(rawPublicKeyBytes)")
// first retrieve the header with the OID for the proper key curve.
let curveOIDHeader: [UInt8]
let curveOIDHeaderLen: Int
switch (keySize) {
case kCryptoExportImportManagerSecp256r1CurveLen:
curveOIDHeader = kCryptoExportImportManagerSecp256r1header
curveOIDHeaderLen = kCryptoExportImportManagerSecp256r1headerLen
case kCryptoExportImportManagerSecp384r1CurveLen:
curveOIDHeader = kCryptoExportImportManagerSecp384r1header
curveOIDHeaderLen = kCryptoExportImportManagerSecp384r1headerLen
case kCryptoExportImportManagerSecp521r1CurveLen:
curveOIDHeader = kCryptoExportImportManagerSecp521r1header
curveOIDHeaderLen = kCryptoExportImportManagerSecp521r1headerLen
default:
curveOIDHeader = []
curveOIDHeaderLen = 0
}
var data = Data(bytes: curveOIDHeader, count: curveOIDHeaderLen)
// now add the raw data from the retrieved public key
data.append(rawPublicKeyBytes)
return data
}
If you have a look at the zip file I sent you then you will find React Native bindings. Tested and works on openssl and other envs like node.
I'm not sure where your problem resides
Is this in ES256ReactNativeBridge.swift ?
Okay, so it's easy to verify the signature using the public key (SecKeyRef / SecKey) reference retreived from security framework. I want to eat my own dogfood and verify the signature using the public key hex string. Any ideas how I can do that?