swift-sodium/Sodium/Box.swift

384 lines
14 KiB
Swift

import Foundation
import Clibsodium
public class Box {
public let MacBytes = Int(crypto_box_macbytes())
public let Primitive = String(validatingUTF8:crypto_box_primitive())
public let BeforenmBytes = Int(crypto_box_beforenmbytes())
public let SealBytes = Int(crypto_box_sealbytes())
public typealias MAC = Bytes
public typealias Beforenm = Bytes
/**
Encrypts a message with a recipient's public key and a sender's secret key.
- Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key.
- Returns: A `Bytes` object containing the nonce and authenticated ciphertext.
*/
public func seal(message: Bytes, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> Bytes? {
guard let (authenticatedCipherText, nonce): (Bytes, Nonce) = seal(message: message, recipientPublicKey: recipientPublicKey, senderSecretKey: senderSecretKey) else {
return nil
}
return nonce + authenticatedCipherText
}
/**
Encrypts a message with a recipient's public key and a sender's secret key using a user-provided nonce.
- Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key.
- Parameter nonce: The user-specified nonce.
- Returns: The authenticated ciphertext.
*/
public func seal(message: Bytes, recipientPublicKey: PublicKey, senderSecretKey: SecretKey, nonce: Nonce) -> Bytes? {
guard recipientPublicKey.count == PublicKeyBytes,
senderSecretKey.count == SecretKeyBytes,
nonce.count == NonceBytes
else { return nil }
var authenticatedCipherText = Bytes(count: message.count + MacBytes)
guard .SUCCESS == crypto_box_easy(
&authenticatedCipherText,
message,
CUnsignedLongLong(message.count),
nonce,
recipientPublicKey,
senderSecretKey
).exitCode else { return nil }
return authenticatedCipherText
}
/**
Encrypts a message with a recipient's public key and a sender's secret key.
- Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key.
- Returns: The authenticated ciphertext and encryption nonce.
*/
public func seal(message: Bytes, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> (authenticatedCipherText: Bytes, nonce: Nonce)? {
guard recipientPublicKey.count == PublicKeyBytes,
senderSecretKey.count == SecretKeyBytes
else { return nil }
var authenticatedCipherText = Bytes(count: message.count + MacBytes)
let nonce = self.nonce()
guard .SUCCESS == crypto_box_easy(
&authenticatedCipherText,
message,
CUnsignedLongLong(message.count),
nonce,
recipientPublicKey,
senderSecretKey
).exitCode else { return nil }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce)
}
/**
Encrypts a message with a recipient's public key and a sender's secret key (detached mode).
- Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key.
- Returns: The authenticated ciphertext, encryption nonce, and authentication tag.
*/
public func seal(message: Bytes, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> (authenticatedCipherText: Bytes, nonce: Nonce, mac: MAC)? {
guard recipientPublicKey.count == PublicKeyBytes,
senderSecretKey.count == SecretKeyBytes
else { return nil }
var authenticatedCipherText = Bytes(count: message.count)
var mac = Bytes(count: MacBytes)
let nonce = self.nonce()
guard .SUCCESS == crypto_box_detached (
&authenticatedCipherText,
&mac,
message, CUnsignedLongLong(message.count),
nonce,
recipientPublicKey,
senderSecretKey
).exitCode else { return nil }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce as Nonce, mac: mac as MAC)
}
/**
Decrypts a message with a sender's public key and the recipient's secret key.
- Parameter nonceAndAuthenticatedCipherText: A `Bytes` object containing the nonce and authenticated ciphertext.
- Parameter senderPublicKey: The sender's public key.
- Parameter recipientSecretKey: The recipient's secret key.
- Returns: The decrypted message.
*/
public func open(nonceAndAuthenticatedCipherText: Bytes, senderPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Bytes? {
guard nonceAndAuthenticatedCipherText.count >= NonceBytes + MacBytes else { return nil }
let nonce = nonceAndAuthenticatedCipherText[..<NonceBytes].bytes as Nonce
let authenticatedCipherText = nonceAndAuthenticatedCipherText[NonceBytes...].bytes
return open(authenticatedCipherText: authenticatedCipherText, senderPublicKey: senderPublicKey, recipientSecretKey: recipientSecretKey, nonce: nonce)
}
/**
Decrypts a message with a sender's public key, recipient's secret key, and encryption nonce.
- Parameter authenticatedCipherText: The authenticated ciphertext.
- Parameter senderPublicKey: The sender's public key.
- Parameter recipientSecretKey: The recipient's secret key.
- Parameter nonce: The encryption nonce.
- Returns: The decrypted message.
*/
public func open(authenticatedCipherText: Bytes, senderPublicKey: PublicKey, recipientSecretKey: SecretKey, nonce: Nonce) -> Bytes? {
guard nonce.count == NonceBytes,
authenticatedCipherText.count >= MacBytes,
senderPublicKey.count == PublicKeyBytes,
recipientSecretKey.count == SecretKeyBytes
else { return nil }
var message = Bytes(count: authenticatedCipherText.count - MacBytes)
guard .SUCCESS == crypto_box_open_easy(
&message,
authenticatedCipherText, UInt64(authenticatedCipherText.count),
nonce,
senderPublicKey,
recipientSecretKey
).exitCode else { return nil }
return message
}
/**
Decrypts a message with a sender's public key, recipient's secret key, encryption nonce, and authentication tag.
- Parameter authenticatedCipherText: The authenticated ciphertext.
- Parameter senderPublicKey: The sender's public key.
- Parameter recipientSecretKey: The recipient's secret key.
- Parameter nonce: The encryption nonce.
- Parameter mac: The authentication tag.
- Returns: The decrypted message.
*/
public func open(authenticatedCipherText: Bytes, senderPublicKey: PublicKey, recipientSecretKey: SecretKey, nonce: Nonce, mac: MAC) -> Bytes? {
guard nonce.count == NonceBytes,
mac.count == MacBytes,
senderPublicKey.count == PublicKeyBytes,
recipientSecretKey.count == SecretKeyBytes
else { return nil }
var message = Bytes(count: authenticatedCipherText.count)
guard .SUCCESS == crypto_box_open_detached(
&message,
authenticatedCipherText,
mac,
UInt64(authenticatedCipherText.count),
nonce,
senderPublicKey,
recipientSecretKey
).exitCode else { return nil }
return message
}
/**
Computes a shared secret key given a public key and a secret key.
Applications that send several messages to the same receiver or receive several messages from the same sender can gain speed by calculating the shared key only once, and reusing it in subsequent operations.
- Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key.
- Returns: The computed shared secret key.
*/
public func beforenm(recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> Bytes? {
var key = Bytes(count: BeforenmBytes)
guard .SUCCESS == crypto_box_beforenm (
&key,
recipientPublicKey,
senderSecretKey
).exitCode else { return nil }
return key
}
/**
Encrypts a message with the shared secret key generated from a recipient's public key and a sender's secret key using `beforenm()`.
- Parameter message: The message to encrypt.
- Parameter beforenm: The shared secret key.
- Returns: The authenticated ciphertext and encryption nonce.
*/
public func seal(message: Bytes, beforenm: Beforenm) -> (authenticatedCipherText: Bytes, nonce: Nonce)? {
guard beforenm.count == BeforenmBytes else { return nil }
var authenticatedCipherText = Bytes(count: message.count + MacBytes)
let nonce = self.nonce()
guard .SUCCESS == crypto_box_easy_afternm (
&authenticatedCipherText,
message, UInt64(message.count),
nonce,
beforenm
).exitCode else { return nil }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce)
}
/**
Decrypts a message with the shared secret key generated from a recipient's public key and a sender's secret key using `beforenm()`.
- Parameter nonceAndAuthenticatedCipherText: A `Bytes` object containing the nonce and authenticated ciphertext.
- Parameter beforenm: The shared secret key.
- Returns: The decrypted message.
*/
public func open(nonceAndAuthenticatedCipherText: Bytes, beforenm: Beforenm) -> Bytes? {
guard nonceAndAuthenticatedCipherText.count >= NonceBytes + MacBytes else { return nil }
let nonce = nonceAndAuthenticatedCipherText[..<NonceBytes].bytes as Nonce
let authenticatedCipherText = nonceAndAuthenticatedCipherText[NonceBytes...].bytes
return open(authenticatedCipherText: authenticatedCipherText, beforenm: beforenm, nonce: nonce)
}
/**
Decrypts a message and encryption nonce with the shared secret key generated from a recipient's public key and a sender's secret key using `beforenm()`.
- Parameter authenticatedCipherText: The authenticated ciphertext.
- Parameter beforenm: The shared secret key.
- Parameter nonce: The encryption nonce.
- Returns: The decrypted message.
*/
public func open(authenticatedCipherText: Bytes, beforenm: Beforenm, nonce: Nonce) -> Bytes? {
guard nonce.count == NonceBytes,
authenticatedCipherText.count >= MacBytes,
beforenm.count == BeforenmBytes
else { return nil }
var message = Bytes(count: authenticatedCipherText.count - MacBytes)
guard .SUCCESS == crypto_box_open_easy_afternm (
&message,
authenticatedCipherText, UInt64(authenticatedCipherText.count),
nonce,
beforenm
).exitCode else { return nil }
return message
}
/**
Encrypts a message with the shared secret key generated from a recipient's public key and a sender's secret key using `beforenm()`.
- Parameter message: The message to encrypt.
- Parameter beforenm: The shared secret key.
- Returns: A `Bytes` object containing the encryption nonce and authenticated ciphertext.
*/
public func seal(message: Bytes, beforenm: Beforenm) -> Bytes? {
guard let (authenticatedCipherText, nonce): (Bytes, Nonce) = seal(
message: message,
beforenm: beforenm
) else { return nil }
return nonce + authenticatedCipherText
}
/**
Encrypts a message with a recipient's public key.
- Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key.
- Returns: The anonymous ciphertext.
*/
public func seal(message: Bytes, recipientPublicKey: Box.PublicKey) -> Bytes? {
guard recipientPublicKey.count == PublicKeyBytes else { return nil }
var anonymousCipherText = Bytes(count: SealBytes + message.count)
guard .SUCCESS == crypto_box_seal (
&anonymousCipherText,
message, UInt64(message.count),
recipientPublicKey
).exitCode else { return nil }
return anonymousCipherText
}
/**
Decrypts a message with the recipient's public key and secret key.
- Parameter anonymousCipherText: A `Bytes` object containing the anonymous ciphertext.
- Parameter senderPublicKey: The recipient's public key.
- Parameter recipientSecretKey: The recipient's secret key.
- Returns: The decrypted message.
*/
public func open(anonymousCipherText: Bytes, recipientPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Bytes? {
guard recipientPublicKey.count == PublicKeyBytes,
recipientSecretKey.count == SecretKeyBytes,
anonymousCipherText.count >= SealBytes
else { return nil }
var message = Bytes(count: anonymousCipherText.count - SealBytes)
guard .SUCCESS == crypto_box_seal_open (
&message,
anonymousCipherText, UInt64(anonymousCipherText.count),
recipientPublicKey,
recipientSecretKey
).exitCode else { return nil }
return message
}
}
extension Box: KeyPairGenerator {
public typealias PublicKey = Bytes
public typealias SecretKey = Bytes
public var SeedBytes: Int { return Int(crypto_box_seedbytes()) }
public var PublicKeyBytes: Int { return Int(crypto_box_publickeybytes()) }
public var SecretKeyBytes: Int { return Int(crypto_box_secretkeybytes()) }
static let newKeypair: (
_ pk: UnsafeMutablePointer<UInt8>,
_ sk: UnsafeMutablePointer<UInt8>
) -> Int32 = crypto_box_keypair
static let keypairFromSeed: (
_ pk: UnsafeMutablePointer<UInt8>,
_ sk: UnsafeMutablePointer<UInt8>,
_ seed: UnsafePointer<UInt8>
) -> Int32 = crypto_box_seed_keypair
public struct KeyPair: KeyPairProtocol {
public typealias PublicKey = Box.PublicKey
public typealias SecretKey = Box.SecretKey
public let publicKey: PublicKey
public let secretKey: SecretKey
}
}
extension Box: NonceGenerator {
public typealias Nonce = Bytes
public var NonceBytes: Int { return Int(crypto_box_noncebytes()) }
}