patbef-iOS/Befund/Core/Security/Curve25519.swift

141 lines
5.8 KiB
Swift

//
// 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
}
}
}
}