This repository has been archived by the owner on Dec 12, 2024. It is now read-only.
generated from TBD54566975/tbd-project-template
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
InMemoryKeyManager implementation (#7)
- Loading branch information
Showing
12 changed files
with
483 additions
and
270 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,93 @@ | ||
public enum Crypto {} | ||
import Foundation | ||
|
||
enum CryptoError: Error { | ||
case illegalArgument(description: String) | ||
} | ||
|
||
enum Crypto { | ||
|
||
/// Generates a private key using the specified algorithm and curve, utilizing the appropriate `KeyGenerator`. | ||
/// - Parameters: | ||
/// - algorithm: The JWA algorithm identifier. | ||
/// - curve: The elliptic curve. Null for algorithms that do not use elliptic curves. | ||
/// - Returns: The generated private key as a JWK object. | ||
static func generatePrivateKey(algorithm: Jwk.Algorithm, curve: Jwk.Curve? = nil) throws -> Jwk { | ||
let keyGenerator = try getKeyGenerator(algorithm: algorithm, curve: curve) | ||
return try keyGenerator.generatePrivateKey() | ||
} | ||
|
||
/// Computes a public key from the given private key, utilizing relevant `KeyGenerator`. | ||
/// - Parameter privateKey: The private key used to compute the public key. | ||
/// - Returns: The computed public key as a JWK object. | ||
static func computePublicKey(privateKey: Jwk) throws -> Jwk { | ||
let keyGenerator = try getKeyGenerator(algorithm: privateKey.algorithm, curve: privateKey.curve) | ||
return try keyGenerator.computePublicKey(privateKey: privateKey) | ||
} | ||
|
||
/// Signs a payload using a private key. | ||
/// - Parameters: | ||
/// - privateKey: The JWK private key to be used for generating the signature. | ||
/// - payload: The data to be signed. | ||
/// - Returns: The digital signature as a byte array. | ||
static func sign<D>(privateKey: Jwk, payload: D) throws -> Data where D: DataProtocol { | ||
let signer = try getSigner(algorithm: privateKey.algorithm, curve: privateKey.curve) | ||
return try signer.sign(privateKey: privateKey, payload: payload) | ||
} | ||
|
||
/// Verifies a signature against a signed payload using a public key. | ||
/// | ||
/// - Parameters: | ||
/// - publicKey: The JWK public key to be used for verifying the signature. | ||
/// - signature: The signature that will be verified. | ||
/// - signedPayload: The data that was signed. | ||
/// - algorithm: The algorithm used for signing/verification, only used if not provided in the JWK. | ||
/// - Returns: Boolean indicating if the publicKey and signature are valid for the given payload. | ||
static func verify<S, D>( | ||
publicKey: Jwk, | ||
signature: S, | ||
signedPayload: D, | ||
algorithm: Jwk.Algorithm? = nil | ||
) throws -> Bool where S: DataProtocol, D: DataProtocol { | ||
let algorithm = publicKey.algorithm ?? algorithm | ||
let verifier = try getVerifier(algorithm: algorithm, curve: publicKey.curve) | ||
return try verifier.verify(publicKey: publicKey, signature: signature, signedPayload: signedPayload) | ||
} | ||
|
||
/// Converts a `Jwk` public key into its byte array representation. | ||
/// - Parameter publicKey: `Jwk` object representing the public key to be converted. | ||
/// - Returns: Data representing the byte-level information of the provided public key | ||
static func publicKeyToBytes(publicKey: Jwk) throws -> Data { | ||
let keyGenerator = try getKeyGenerator(algorithm: publicKey.algorithm, curve: publicKey.curve) | ||
return try keyGenerator.publicKeyToBytes(publicKey) | ||
} | ||
|
||
// MARK: Private | ||
|
||
/// Retrieves a `KeyGenerator` based on the provided algorithm and curve. | ||
/// - Parameters: | ||
/// - algorithm: The cryptographic algorithm to find a key generator for. | ||
/// - curve: The cryptographic curve to find a key generator for. | ||
/// - Returns: The corresponding `KeyGenerator`. | ||
private static func getKeyGenerator(algorithm: Jwk.Algorithm?, curve: Jwk.Curve? = nil) throws -> KeyGenerator { | ||
switch (algorithm, curve) { | ||
case (nil, .secp256k1), | ||
(Secp256k1.shared.algorithm, nil), | ||
(Secp256k1.shared.algorithm, .secp256k1): | ||
return Secp256k1.shared | ||
case (Ed25519.shared.algorithm, .ed25519): | ||
return Ed25519.shared | ||
default: | ||
throw CryptoError.illegalArgument( | ||
description: "Algorithm \(algorithm?.rawValue ?? "nil") not supported" | ||
) | ||
} | ||
} | ||
|
||
private static func getSigner(algorithm: Jwk.Algorithm?, curve: Jwk.Curve? = nil) throws -> Signer { | ||
return try getKeyGenerator(algorithm: algorithm, curve: curve) as! Signer | ||
} | ||
|
||
private static func getVerifier(algorithm: Jwk.Algorithm?, curve: Jwk.Curve? = nil) throws -> Signer { | ||
return try getSigner(algorithm: algorithm, curve: curve) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import Foundation | ||
|
||
class InMemoryKeyManager { | ||
|
||
/// Backing in-memory store to store generated keys. | ||
private var keyStore = [String: Jwk]() | ||
|
||
} | ||
|
||
// MARK: - KeyManager | ||
|
||
extension InMemoryKeyManager: KeyManager { | ||
|
||
func generatePrivateKey(algorithm: Jwk.Algorithm, curve: Jwk.Curve? = nil) throws -> String { | ||
let jwk = try Crypto.generatePrivateKey(algorithm: algorithm, curve: curve) | ||
let alias = try getDeterministicAlias(key: jwk) | ||
keyStore[alias] = jwk | ||
|
||
return alias | ||
} | ||
|
||
func getPublicKey(keyAlias: String) throws -> Jwk? { | ||
if let privateKey = keyStore[keyAlias] { | ||
return try Crypto.computePublicKey(privateKey: privateKey) | ||
} else { | ||
return nil | ||
} | ||
} | ||
|
||
func sign<D>(keyAlias: String, payload: D) throws -> Data where D: DataProtocol { | ||
guard let privateKey = keyStore[keyAlias] else { | ||
throw KeyManagerError.keyAliasNotFound | ||
} | ||
|
||
return try Crypto.sign(privateKey: privateKey, payload: payload) | ||
} | ||
|
||
func getDeterministicAlias(key: Jwk) throws -> String { | ||
let alias: String | ||
|
||
if let keyIdentifier = key.keyIdentifier { | ||
alias = keyIdentifier | ||
} else { | ||
alias = try key.thumbprint() | ||
} | ||
|
||
return alias | ||
} | ||
} |
Oops, something went wrong.