Open louischan-oursky opened 1 year ago
On iOS, the following snippet generate a P256 key pair in the Secure Enclave and export the public key
let flags: SecAccessControlCreateFlags = [.biometryCurrentSet, .and, .privateKeyUsage]
let access = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
flags,
nil)!
let tag = "tag"
let attributes: NSDictionary = [
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits: 256,
kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
kSecPrivateKeyAttrs: [
kSecAttrIsPermanent: true,
kSecAttrApplicationTag: tag,
kSecAttrAccessControl: access
]
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes, &error) else {
throw error!.takeRetainedValue() as Error
}
let publicKey = SecKeyCopyPublicKey(privateKey)!
let cfData = SecKeyCopyExternalRepresentation(publicKey, nil)!
let data = cfData as Data
let base64 = data.base64EncodedString()
In Go, we can construct the JWK
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"encoding/base64"
"encoding/json"
"fmt"
// This is v1 API
"github.com/lestrrat-go/jwx/jwk"
)
func main() {
publicKeyBase64 := "BBnS2sXMxybCu2sS43Kmv1+zYwpMJNAeAjnc3fTyDJQti0vhB+FDcBT3EHQ2Taj5+O+meX/zRaCxHT9gMGJpzic="
publicKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64)
if err != nil {
panic(err)
}
curve := elliptic.P256()
x, y := elliptic.Unmarshal(curve, publicKeyBytes)
if x == nil {
panic(fmt.Errorf("invalid key"))
}
publicKey := &ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
}
jwkKey, err := jwk.New(publicKey)
if err != nil {
panic(err)
}
jsonBytes, err := json.MarshalIndent(jwkKey, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("%v\n", string(jsonBytes))
// {
// "crv": "P-256",
// "kty": "EC",
// "x": "GdLaxczHJsK7axLjcqa_X7NjCkwk0B4COdzd9PIMlC0",
// "y": "i0vhB-FDcBT3EHQ2Taj5-O-meX_zRaCxHT9gMGJpzic"
// }
}
The update does not effect the public API. To take effect, biometric has to be disabled, and enabled again.