// // Curve25519.swift // Befund // // Created by Irakli Abetschkhrischwili on 29.04.22. // Copyright © 2022 MVZ Dr. Stein und Kollegen. All rights reserved. import Foundation import CryptoKit extension Core.Security { public struct Curve25519 { /** * Generates the KeyPair with Private & Public Keys * * @return returns KeyPair with Public & Private Keys(incl. Signing Private & Public Keys) */ static func GenerateKeyPair() -> KeyPair { let result: KeyPair = KeyPair() let privateKey = CryptoKit.Curve25519.KeyAgreement.PrivateKey() let publicKey = privateKey.publicKey let signingPrivateKey = CryptoKit.Curve25519.Signing.PrivateKey() let signingPublicKey = signingPrivateKey.publicKey result.PrivateKey = privateKey.rawRepresentation.base64EncodedString() result.PublicKey = publicKey.rawRepresentation.base64EncodedString() result.SigningPrivateKey = signingPrivateKey.rawRepresentation.base64EncodedString() result.SigningPublicKey = signingPublicKey.rawRepresentation.base64EncodedString() return result } /* * Creates KeyPair by private & public keys(base64 encoded) */ static func CreateKeyPair(_privateKey: String, _publicKey: String) -> KeyPair { let result: KeyPair = KeyPair() let privateKey = try! CryptoKit.Curve25519.KeyAgreement.PrivateKey(rawRepresentation: Data(base64Encoded: _privateKey)!) let publicKey = try! CryptoKit.Curve25519.KeyAgreement.PublicKey(rawRepresentation: Data(base64Encoded: _publicKey)!) let signingPrivateKey = CryptoKit.Curve25519.Signing.PrivateKey() let signingPublicKey = signingPrivateKey.publicKey result.PrivateKey = privateKey.rawRepresentation.base64EncodedString() result.PublicKey = publicKey.rawRepresentation.base64EncodedString() result.SigningPrivateKey = signingPrivateKey.rawRepresentation.base64EncodedString() result.SigningPublicKey = signingPublicKey.rawRepresentation.base64EncodedString() return result } /** * Validates a ED25519 Signature with message and public key of sender * * @param signature - signature that should be validated * @param message - message that was signed * @param publicKey - public key that was used by sender for the message to sign it * @return returns true if valid */ static func CheckValid(signature: Data, message: Data, publicKey: Data) -> Bool { let key = try! CryptoKit.Curve25519.Signing.PublicKey(rawRepresentation: publicKey) return key.isValidSignature(signature, for: message) } /** * KeyPair with Private & Public Key and Signature Keys */ public class KeyPair { public var PrivateKey: String! public var PublicKey: String! public var SigningPublicKey: String! public var SigningPrivateKey: String! public func GetSignature(signingValue: String) -> String? { var result: String? = nil do { let signingData = signingValue.data(using: .utf8)! let privateKeyRaw: Data? = Data(base64Encoded: self.SigningPrivateKey!) let privateKey = try! CryptoKit.Curve25519.Signing.PrivateKey(rawRepresentation: privateKeyRaw!) result = try privateKey.signature(for: signingData).base64EncodedString() } catch { Core.Log.Error(err: error, namespace: "Core.Security.Curve25519.KeyPair", method: "GetSignature(String)") } return result } /** * Returns a shared key with the public key * * @peerPublicKeyBase64 - Public key of peer in base64 string format * @return returns shared key as byte array */ public func GetSharedKey(peerPublicKeyBase64: String?) -> CryptoKit.SymmetricKey? { var result: CryptoKit.SymmetricKey? = nil if(peerPublicKeyBase64 != nil) { let privateKeyRaw: Data? = Data(base64Encoded: self.PrivateKey!) if(privateKeyRaw != nil) { let privateKey = try! CryptoKit.Curve25519.KeyAgreement.PrivateKey(rawRepresentation: privateKeyRaw!) let peerPublicKeyRaw: Data? = Data(base64Encoded: peerPublicKeyBase64!) if(peerPublicKeyRaw != nil) { let peerPublicKey = try! CryptoKit.Curve25519.KeyAgreement.PublicKey(rawRepresentation: peerPublicKeyRaw!) let sharedSecret = try! privateKey.sharedSecretFromKeyAgreement(with: peerPublicKey) let protocolSalt = "" result = sharedSecret.hkdfDerivedSymmetricKey(using: CryptoKit.SHA512.self, salt: protocolSalt.data(using: .ascii)!, sharedInfo: Data(), outputByteCount: 32) } } } return result } } } }