Core LibP2P cryptography API for interacting with various Keys, Hashes and Ciphers
LibP2PCrypto is an API / abstraction layer for commonly used cryptography within the LibP2P ecosystem. This library...
This package currently doesn't support Blake2b, Blake2s & Blake3. If you're up for the challenge, please feel free to add support!
‼️ This is a work in progress ‼️
Include the following dependency in your Package.swift file
let package = Package(
...
dependencies: [
...
.package(url: "https://github.com/swift-libp2p/swift-libp2p-crypto.git", .upToNextMajor(from: "0.0.1"))
],
...
.target(
...
dependencies: [
...
.product(name: "LibP2PCrypto", package: "swift-libp2p-crypto"),
]),
...
)
check out the tests for more examples
import LibP2PCrypto
/// Generate a new Public / Private Key Pair
let rsaKeyPair = try LibP2PCrypto.Keys.generateKeyPair(.RSA(bits: .B2048))
rsaKeyPair.keyType // -> .rsa
rsaKeyPair.publicKey // -> PublicKey
rsaKeyPair.publicKey.data // -> raw public key data
rsaKeyPair.privateKey // -> optional(PrivateKey)
/// Key Types
try LibP2PCrypto.Keys.generateKeyPair(.RSA(bits: .B2048)) // RSA w/ Bit Options... 1024, 2048, 3072, 4096
try LibP2PCrypto.Keys.generateKeyPair(.Ed25519) // Ed25519 Elliptic Key
try LibP2PCrypto.Keys.generateKeyPair(.Secp256k1) // Secp256k1 Key
/// Importing Marshalled Keys
let pubKey = try LibP2PCrypto.Keys.importMarshaledPublicKey(marshaledPublicKeyData)
/// or using a marshaled private key...
let privateKey = try LibP2PCrypto.Keys.importMarshaledPrivateKey(marshaledPrivateKeyData)
/// or instantiate a KeyPair instead... (if you pass in a public key, the private key will be nil, if you pass in a private key, both public and private keys will be imported/extracted)
let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: marshaledPrivateKeyData)
let keyPair = try LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey: marshaledPrivateKeyAsBase64String, base: .base64Pad) // Or you can use a String encoding of the key data
/// Importing PEM files (PEM, Encrypted PEM, DER and CERTIFICATES are supported. See the tests for more examples...)
let pem = """
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEACM3Nzttt7KmXG9qDEYys++oQ9G749jqrbRRs92BUzpA=
-----END PUBLIC KEY-----
"""
let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: pem)
keyPair.keyType // -> .ed25519
keyPair.publicKey // -> Public Key (can be used for verifying signed messages...)
keyPair.privateKey // -> nil (private key is nil when importing public keys...)
/// You can import encrypted PEM files as well...
let keyPair = try LibP2PCrypto.Keys.KeyPair(pem: encryptedPem, password: "mypassword")
/// Once you have a KeyPair, you can use it to....
/// Sign & Verify Messages
let keyPair = try LibP2PCrypto.Keys.generateKeyPair(.Ed25519)
let message = "Hello, world!".data(using: .utf8)!
let signedData = try keyPair.privateKey!.sign(message: message)
if try keyPair.publicKey.verfiy(signedData, for: message) {
// The signature is valid! It means that the public key used to verify the signed message was derived from the same private key that signed the message
} else {
// Invalid signature. This public key does not belong to the private key that signed the message.
}
/// If you want to share the public key, you can export it by marshaling it
try keyPair.publicKey.marshal()
/// If you want to safely store the Private key between sessions you can export it as an encrypted PEM String
try keyPair.exportEncryptedPrivatePEMString(withPassword "mypassword")
/// AES Cipher (streaming encryption cipher)
let message = "Hello World!"
let key256 = "12345678901234561234567890123456" // 32 bytes for AES256
let iv = "abcdefghijklmnop" // 16 bytes for AES128
let aes256Key = try LibP2PCrypto.AES.createKey(key: key256, iv: iv)
let encrypted = try aes256Key.encrypt(message)
let decrypted:String = try aes256Key.decrypt(encrypted)
/// AES GCM
let message = "Hello World!"
let encrypted = try message.encryptGCM(password: "mypassword")
let decrypted = try encrypted.decryptGCM(password: "mypassword")
/// HMAC (Hashed Message Authentication Codes)
let message = "Hello World!"
let key = "secret"
let hmacKeyLocal = LibP2PCrypto.HMAC.create(algorithm: .SHA256, secret: key)
let hmacKeyRemote = LibP2PCrypto.HMAC.create(algorithm: .SHA256, secret: key)
let encrypted = hmacKeyLocal.encrypt(message)
hmacKeyRemote.verify(message, hash: encrypted) // -> Returns true. Correct data + correct HMAC == true
hmacKeyRemote.verify("HellØ world!", hash: encrypted) // -> Returns false. Corrupted data + correct HMAC == false
/// PBKDF2 (password based key derivation function 2)
let key = PBKDF2.SHA1(password: "mypassword", salt: salt, keyByteCount: 16, rounds: itterations)
/// Generate Keys
LibP2PCrypto.Keys.generateKeyPair(_ type:KeyPairType) throws -> KeyPair
/// Import Marshaled Keys
LibP2PCrypto.Keys.KeyPair(marshaledPublicKey str:String, base:BaseEncoding) throws
LibP2PCrypto.Keys.KeyPair(marshaledPublicKey data:Data) throws
LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey str:String, base:BaseEncoding) throws
LibP2PCrypto.Keys.KeyPair(marshaledPrivateKey data:Data) throws
/// Import PEM formatted Keys
LibP2PCrypto.Keys.KeyPair(pem:String, password:String? = nil) throws -> KeyPair
LibP2PCrypto.Keys.KeyPair(pem:Data, password:String? = nil) throws -> KeyPair
/// Sign & Verify
RawPrivateKey.sign(message: Data) throws -> Data
RawPublicKey.verfiy(_ signature: Data, for expectedData:Data) throws -> Bool
/// AES CIPHER
LibP2PCrypto.AES.createKey(key:String, iv:String) throws -> AESKey
LibP2PCrypto.AES.AESKey.encrypt(_ data:Data) throws -> Data
LibP2PCrypto.AES.AESKey.decrypt(_ data: Data) throws -> Data
/// HMAC
LibP2PCrypto.HMAC.create(algorithm:CryptoAlgorithm, secret:String) -> LibP2PCrypto.HMAC.HMACKey
LibP2PCrypto.HMAC.HMACKey.encrypt(_ message:Data) -> Data
LibP2PCrypto.HMAC.HMACKey.verify(_ data:Data, hash:Data) -> Bool
/// PBKDF2
LibP2PCrypto.PBKDF2.SHA1(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data?
LibP2PCrypto.PBKDF2.SHA256(password: String, salt: Data, keyByteCount: Int = 16, rounds: Int = 32767) -> Data?
LibP2PCrypto.PBKDF2.SHA512(password: String, salt: Data, keyByteCount: Int, rounds: Int) -> Data?
Contributions are welcomed! This code is very much a proof of concept. I can guarantee you there's a better / safer way to accomplish the same results. Any suggestions, improvements, or even just critques, are welcome!
Let's make this code better together! 🤝
MIT © 2022 Breth Inc.