This commit is contained in:
Sydney Morton 2022-10-10 15:04:01 -07:00
Родитель 17443df066
Коммит 9f4cf7e375
10 изменённых файлов: 101 добавлений и 28 удалений

Просмотреть файл

@ -4,9 +4,10 @@
*--------------------------------------------------------------------------------------------*/
public protocol CryptoOperating {
func verify(signature: Data, forMessageHash messageHash: Data, usingPublicKey publicKey: PublicKey) throws -> Bool
func sign(messageHash: Data, usingSecret secret: VCCryptoSecret) throws -> Data
func hash(message: Data, algorithm: SupportedHashAlgorithm) -> Data
func getPublicKey(fromSecret secret: VCCryptoSecret) throws -> PublicKey
func verify(signature: Data, forMessageHash messageHash: Data, usingPublicKey publicKey: PublicKey) throws -> Bool
}
enum CryptoOperationsError: Error {
@ -24,6 +25,16 @@ public struct CryptoOperations: CryptoOperating {
return try algorithm.sign(messageHash: messageHash)
}
public func hash(message: Data, algorithm: SupportedHashAlgorithm) -> Data {
switch algorithm {
case .SHA256:
return Sha256().hash(data: message)
case .SHA512:
return Sha512().hash(data: message)
}
}
/// Only support Secp256k1 public key retrieval.
public func getPublicKey(fromSecret secret: VCCryptoSecret) throws -> PublicKey {
return try Secp256k1(secret: secret).getPublicKey()
}

Просмотреть файл

@ -3,7 +3,12 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
public enum SupportedAlgorithms: String {
public enum SupportedVerificationAlgorithm: String {
case ED25519 = "ED25519"
case Secp256k1 = "SECP256K1"
}
public enum SupportedHashAlgorithm {
case SHA256
case SHA512
}

Просмотреть файл

@ -26,11 +26,11 @@ struct IdentifierFormatter: IdentifierFormatting {
}
func createIonLongFormDid(recoveryKey: ECPublicJwk,
updateKey: ECPublicJwk,
didDocumentKeys: [ECPublicJwk],
serviceEndpoints: [IdentifierDocumentServiceEndpoint]) throws -> String {
updateKey: ECPublicJwk,
didDocumentKeys: [ECPublicJwk],
serviceEndpoints: [IdentifierDocumentServiceEndpoint]) throws -> String {
let document = IONDocumentModel(fromJwks: didDocumentKeys, andServiceEndpoints: serviceEndpoints)
let document = IONDocumentModel(fromJwks: didDocumentKeys.map { key in key.toJWK() }, andServiceEndpoints: serviceEndpoints)
let patches = [IONDocumentPatch(action: IdentifierFormatter.replaceAction, document: document)]
let commitmentHash = try self.createCommitmentHash(usingJwk: updateKey)

Просмотреть файл

@ -9,14 +9,14 @@ public struct IdentifierDocumentPublicKey: Codable, Equatable {
let id: String?
let type: String
let controller: String?
let publicKeyJwk: ECPublicJwk
let publicKeyJwk: JWK
let purposes: [String]?
public init(id: String?,
type: String,
controller: String?,
publicKeyJwk: ECPublicJwk,
purposes: [String]?) {
type: String,
controller: String?,
publicKeyJwk: JWK,
purposes: [String]?) {
self.id = id
self.type = type
self.controller = controller
@ -24,7 +24,7 @@ public struct IdentifierDocumentPublicKey: Codable, Equatable {
self.purposes = purposes
}
init(fromJwk key: ECPublicJwk) {
init(fromJwk key: JWK) {
self.init(id: key.keyId, type: VCEntitiesConstants.SUPPORTED_PUBLICKEY_TYPE, controller: nil, publicKeyJwk: key, purposes: [VCEntitiesConstants.PUBLICKEY_AUTHENTICATION_PURPOSE_V1])
}
}

Просмотреть файл

@ -9,7 +9,7 @@ struct IONDocumentModel: Codable {
let publicKeys: [IdentifierDocumentPublicKey]
let services: [IdentifierDocumentServiceEndpoint]?
init(fromJwks jwks: [ECPublicJwk], andServiceEndpoints services: [IdentifierDocumentServiceEndpoint]) {
init(fromJwks jwks: [JWK], andServiceEndpoints services: [IdentifierDocumentServiceEndpoint]) {
var keys: [IdentifierDocumentPublicKey] = []
for jwk in jwks {
keys.append(IdentifierDocumentPublicKey(fromJwk: jwk))

Просмотреть файл

@ -65,7 +65,7 @@ public struct JwsToken<T: Claims> {
self.signature = try signer.sign(token: self, withSecret: secret)
}
public func verify(using verifier: TokenVerifying, withPublicKey key: any PublicJwk) throws -> Bool {
public func verify(using verifier: TokenVerifying, withPublicKey key: JWK) throws -> Bool {
return try verifier.verify(token: self, usingPublicKey: key)
}

Просмотреть файл

@ -7,7 +7,7 @@ import VCCrypto
public protocol TokenVerifying {
func verify<T>(token: JwsToken<T>, usingPublicKey key: any PublicJwk) throws -> Bool
func verify<T>(token: JwsToken<T>, usingPublicKey key: JWK) throws -> Bool
}

Просмотреть файл

@ -16,6 +16,22 @@ public protocol PublicJwk: Codable, Equatable {
var y: String { get }
}
public struct JWK: Codable, Equatable {
let keyType: String?
public let keyId: String?
let use: String?
let keyOperations: [String]?
let algorithm: String?
let curve: String?
let x: String?
let y: String?
enum CodingKeys: String, CodingKey {
case curve = "crv"
case keyType, keyId, use, keyOperations, algorithm, x, y
}
}
public struct ECPublicJwk: PublicJwk {
public let keyType: String
public let keyId: String?
@ -52,6 +68,18 @@ public struct ECPublicJwk: PublicJwk {
self.init(x: x, y: y, keyId: kid)
}
public func toJWK() -> JWK
{
return JWK(keyType: keyType,
keyId: keyId,
use: use,
keyOperations: keyOperations,
algorithm: algorithm,
curve: curve,
x: x,
y: y)
}
func getMinimumAlphabeticJwk() -> String {
return "{\"crv\":\"\(self.curve)\",\"kty\":\"\(self.keyType)\",\"x\":\"\(self.x)\",\"y\":\"\(self.y)\"}"
}

Просмотреть файл

@ -12,13 +12,10 @@ enum Secp256k1SignerError: Error {
/// TODO: refactor class to be a generic signer.
public struct Secp256k1Signer: TokenSigning {
private let hashAlgorithm: Sha256
private let cryptoOperations: CryptoOperating
public init(cryptoOperations: CryptoOperating = CryptoOperations(), andHashAlgorithm hashAlg: Sha256 = Sha256()) {
public init(cryptoOperations: CryptoOperating = CryptoOperations()) {
self.cryptoOperations = cryptoOperations
self.hashAlgorithm = hashAlg
}
public func sign<T>(token: JwsToken<T>, withSecret secret: VCCryptoSecret) throws -> Signature {
@ -29,7 +26,8 @@ public struct Secp256k1Signer: TokenSigning {
throw VCTokenError.unableToParseData
}
let hashedMessage = hashAlgorithm.hash(data: messageData)
let hashedMessage = cryptoOperations.hash(message: messageData, algorithm: .SHA256)
return try cryptoOperations.sign(messageHash: hashedMessage, usingSecret: secret)
}

Просмотреть файл

@ -5,16 +5,20 @@
import VCCrypto
enum TokenVerifierError: Error {
case unsupportedAlgorithmFoundInJWK
case malformedJWK
}
public struct TokenVerifier: TokenVerifying {
private let cryptoOperations: CryptoOperating
private let hashAlgorithm: Sha256 = Sha256()
public init(cryptoOperations: CryptoOperating = CryptoOperations()) {
self.cryptoOperations = cryptoOperations
}
public func verify<T>(token: JwsToken<T>, usingPublicKey key: any PublicJwk) throws -> Bool {
public func verify<T>(token: JwsToken<T>, usingPublicKey key: JWK) throws -> Bool {
guard let signature = token.signature else {
return false
@ -24,15 +28,42 @@ public struct TokenVerifier: TokenVerifying {
throw VCTokenError.unableToParseString
}
guard let x = Data(base64URLEncoded: key.x),
let y = Data(base64URLEncoded: key.y),
let secpKey = Secp256k1PublicKey(x: x, y: y) else {
throw VCTokenError.unableToParseString
let hashedMessage = cryptoOperations.hash(message: encodedMessage, algorithm: .SHA256)
return try cryptoOperations.verify(signature: signature, forMessageHash: hashedMessage, usingPublicKey: transformKey(key: key))
}
private func transformKey(key: JWK) throws -> PublicKey {
switch key.curve?.uppercased() {
case SupportedVerificationAlgorithm.Secp256k1.rawValue:
return try transformSecp256k1(key: key)
case SupportedVerificationAlgorithm.ED25519.rawValue:
return try transformED25519(key: key)
default:
throw TokenVerifierError.unsupportedAlgorithmFoundInJWK
}
let hashedMessage = self.hashAlgorithm.hash(data: encodedMessage)
}
private func transformSecp256k1(key: JWK) throws -> Secp256k1PublicKey {
guard let x = key.x, let y = key.y,
let encodedX = Data(base64URLEncoded: x),
let encodedY = Data(base64URLEncoded: y),
let secpKey = Secp256k1PublicKey(x: encodedX, y: encodedY) else {
throw TokenVerifierError.malformedJWK
}
return try cryptoOperations.verify(signature: signature, forMessageHash: hashedMessage, usingPublicKey: secpKey)
return secpKey
}
private func transformED25519(key: JWK) throws -> ED25519PublicKey {
guard let x = key.x,
let encodedX = Data(base64URLEncoded: x),
let edKey = ED25519PublicKey(x: encodedX) else {
throw TokenVerifierError.malformedJWK
}
return edKey
}
}