First pass to make the code a tiny bit more consistent

This commit is contained in:
Frank Denis 2017-09-23 20:08:19 +02:00
parent 79ac24af27
commit 494716a51d
17 changed files with 581 additions and 705 deletions

View File

@ -144,8 +144,7 @@ let stream_enc = sodium.secretStream.xchacha20poly1305.initPush(secretKey: secre
let header = stream_enc.header() let header = stream_enc.header()
let encrypted1 = stream_enc.push(message: message1)! let encrypted1 = stream_enc.push(message: message1)!
let encrypted2 = stream_enc.push(message: message2)! let encrypted2 = stream_enc.push(message: message2)!
let encrypted3 = stream_enc.push(message: message3, let encrypted3 = stream_enc.push(message: message3, tag: .FINAL)!
tag: SecretStream.XChaCha20Poly1305.Tag.FINAL)!
/* stream decryption */ /* stream decryption */
@ -257,9 +256,9 @@ let aliceKeyPair = sodium.keyExchange.keyPair()!
let bobKeyPair = sodium.keyExchange.keyPair()! let bobKeyPair = sodium.keyExchange.keyPair()!
let sessionKeyPairForAlice = sodium.keyExchange.sessionKeyPair(publicKey: aliceKeyPair.publicKey, let sessionKeyPairForAlice = sodium.keyExchange.sessionKeyPair(publicKey: aliceKeyPair.publicKey,
secretKey: aliceKeyPair.secretKey, otherPublicKey: bobKeyPair.publicKey, side: .client)! secretKey: aliceKeyPair.secretKey, otherPublicKey: bobKeyPair.publicKey, side: .CLIENT)!
let sessionKeyPairForBob = sodium.keyExchange.sessionKeyPair(publicKey: bobKeyPair.publicKey, let sessionKeyPairForBob = sodium.keyExchange.sessionKeyPair(publicKey: bobKeyPair.publicKey,
secretKey: bobKeyPair.secretKey, otherPublicKey: aliceKeyPair.publicKey, side: .server)! secretKey: bobKeyPair.secretKey, otherPublicKey: aliceKeyPair.publicKey, side: .SERVER)!
let aliceToBobKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.tx, sessionKeyPairForBob.xx) // true let aliceToBobKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.tx, sessionKeyPairForBob.xx) // true
let bobToAliceKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.rx, sessionKeyPairForBob.tx) // true let bobToAliceKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.rx, sessionKeyPairForBob.tx) // true
@ -365,7 +364,7 @@ Constant-time base64 encoding
```swift ```swift
let sodium = Sodium() let sodium = Sodium()
let b64 = sodium.utils.bin2base64("data".toData()!)! let b64 = sodium.utils.bin2base64("data".toData()!)!
let b64_2 = sodium.utils.bin2base64("data".toData()!, variant: Utils.Base64Variant.URLSAFE_NO_PADDING)! let b64_2 = sodium.utils.bin2base64("data".toData()!, variant: .URLSAFE_NO_PADDING)!
``` ```
Base64 decoding Base64 decoding
@ -374,7 +373,7 @@ Base64 decoding
```swift ```swift
let data1 = sodium.utils.base642bin(b64) let data1 = sodium.utils.base642bin(b64)
let data2 = sodium.utils.base642bin(b64, ignore: " \n") let data2 = sodium.utils.base642bin(b64, ignore: " \n")
let data3 = sodium.utils.base642bin(b64_2, variant: Utils.Base64Variant.URLSAFE_NO_PADDING, ignore: " \n") let data3 = sodium.utils.base642bin(b64_2, variant: .URLSAFE_NO_PADDING, ignore: " \n")
``` ```
Helpers to build custom constructions Helpers to build custom constructions

View File

@ -2,9 +2,6 @@
// Auth.swift // Auth.swift
// Sodium // Sodium
// //
// Created by WANG Jie on 03/04/2017.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -12,12 +9,12 @@ import libsodium
public class Auth { public class Auth {
public let KeyBytes = Int(crypto_auth_keybytes()) public let KeyBytes = Int(crypto_auth_keybytes())
public let Bytes = Int(crypto_auth_bytes()) public let Bytes = Int(crypto_auth_bytes())
public typealias SecretKey = Data public typealias SecretKey = Data
/** /**
Generates a key to compute authentication tags. Generates a key to compute authentication tags.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> SecretKey? { public func key() -> SecretKey? {
@ -27,61 +24,55 @@ public class Auth {
} }
return secretKey return secretKey
} }
/** /**
Computes an authentication tag for a message using a key Computes an authentication tag for a message using a key
- Parameter message: The message to authenticate. - Parameter message: The message to authenticate.
- Parameter secretKey: The key required to create and verify messages. - Parameter secretKey: The key required to create and verify messages.
- Returns: The computed authentication tag. - Returns: The computed authentication tag.
*/ */
public func tag(message: Data, secretKey: SecretKey) -> Data? { public func tag(message: Data, secretKey: SecretKey) -> Data? {
if secretKey.count != KeyBytes { if secretKey.count != KeyBytes {
return nil return nil
} }
var tag = Data(count: Bytes) var tag = Data(count: Bytes)
let result = tag.withUnsafeMutableBytes { tagPtr in let result = tag.withUnsafeMutableBytes { tagPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_auth( crypto_auth( tagPtr,
tagPtr, messagePtr, CUnsignedLongLong(message.count),
messagePtr, secretKeyPtr)
CUnsignedLongLong(message.count),
secretKeyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return tag return tag
} }
/** /**
Verifies that an authentication tag is valid for a message and a key Verifies that an authentication tag is valid for a message and a key
- Parameter message: The message to verify. - Parameter message: The message to verify.
- Parameter secretKey: The key required to create and verify messages. - Parameter secretKey: The key required to create and verify messages.
- Parameter tag: The authentication tag. - Parameter tag: The authentication tag.
- Returns: `true` if verification is successful. - Returns: `true` if the verification is successful.
*/ */
public func verify(message: Data, secretKey: SecretKey, tag: Data) -> Bool { public func verify(message: Data, secretKey: SecretKey, tag: Data) -> Bool {
if secretKey.count != KeyBytes { if secretKey.count != KeyBytes {
return false return false
} }
return tag.withUnsafeBytes { tagPtr in return tag.withUnsafeBytes { tagPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_auth_verify( crypto_auth_verify(
tagPtr, tagPtr,
messagePtr, messagePtr, CUnsignedLongLong(message.count), secretKeyPtr) == 0
CUnsignedLongLong(message.count), secretKeyPtr) == 0
} }
} }
} }

View File

@ -2,9 +2,6 @@
// Box.swift // Box.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/28/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -18,75 +15,74 @@ public class Box {
public let Primitive = String.init(validatingUTF8:crypto_box_primitive()) public let Primitive = String.init(validatingUTF8:crypto_box_primitive())
public let BeforenmBytes = Int(crypto_box_beforenmbytes()) public let BeforenmBytes = Int(crypto_box_beforenmbytes())
public let SealBytes = Int(crypto_box_sealbytes()) public let SealBytes = Int(crypto_box_sealbytes())
public typealias PublicKey = Data public typealias PublicKey = Data
public typealias SecretKey = Data public typealias SecretKey = Data
public typealias Nonce = Data public typealias Nonce = Data
public typealias MAC = Data public typealias MAC = Data
public typealias Beforenm = Data public typealias Beforenm = Data
public struct KeyPair { public struct KeyPair {
public let publicKey: PublicKey public let publicKey: PublicKey
public let secretKey: SecretKey public let secretKey: SecretKey
public init(publicKey: PublicKey, secretKey: SecretKey) { public init(publicKey: PublicKey, secretKey: SecretKey) {
self.publicKey = publicKey self.publicKey = publicKey
self.secretKey = secretKey self.secretKey = secretKey
} }
} }
/** /**
Generates an encryption secret key and a corresponding public key. Generates an encryption secret key and a corresponding public key.
- Returns: A key pair containing the secret key and public key. - Returns: A key pair containing the secret key and public key.
*/ */
public func keyPair() -> KeyPair? { public func keyPair() -> KeyPair? {
var pk = Data(count: PublicKeyBytes) var pk = Data(count: PublicKeyBytes)
var sk = Data(count: SecretKeyBytes) var sk = Data(count: SecretKeyBytes)
let result = pk.withUnsafeMutableBytes { pkPtr in let result = pk.withUnsafeMutableBytes { pkPtr in
return sk.withUnsafeMutableBytes { skPtr in sk.withUnsafeMutableBytes { skPtr in
return crypto_box_keypair(pkPtr, skPtr) crypto_box_keypair(pkPtr, skPtr)
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return KeyPair(publicKey: pk, secretKey: sk) return KeyPair(publicKey: pk, secretKey: sk)
} }
/** /**
Generates an encryption secret key and a corresponding public key derived from a seed. Generates an encryption secret key and a corresponding public key derived from a seed.
- Parameter seed: The value from which to derive the secret and public key. - Parameter seed: The value from which to derive the secret and public key.
- Returns: A key pair containing the secret key and public key. - Returns: A key pair containing the secret key and public key.
*/ */
public func keyPair(seed: Data) -> KeyPair? { public func keyPair(seed: Data) -> KeyPair? {
if seed.count != SeedBytes { if seed.count != SeedBytes {
return nil return nil
} }
var pk = Data(count: PublicKeyBytes) var pk = Data(count: PublicKeyBytes)
var sk = Data(count: SecretKeyBytes) var sk = Data(count: SecretKeyBytes)
let result = pk.withUnsafeMutableBytes { pkPtr in let result = pk.withUnsafeMutableBytes { pkPtr in
return sk.withUnsafeMutableBytes { skPtr in sk.withUnsafeMutableBytes { skPtr in
return seed.withUnsafeBytes { seedPtr in seed.withUnsafeBytes { seedPtr in
return crypto_box_seed_keypair(pkPtr, skPtr, seedPtr) crypto_box_seed_keypair(pkPtr, skPtr, seedPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return KeyPair(publicKey: pk, secretKey: sk) return KeyPair(publicKey: pk, secretKey: sk)
} }
/**
Generates a random nonce.
- Returns: A nonce.
*/
public func nonce() -> Nonce { public func nonce() -> Nonce {
var nonce = Data(count: NonceBytes) var nonce = Data(count: NonceBytes)
nonce.withUnsafeMutableBytes { noncePtr in nonce.withUnsafeMutableBytes { noncePtr in
@ -94,14 +90,14 @@ public class Box {
} }
return nonce return nonce
} }
/** /**
Encrypts a message with a recipient's public key and a sender's secret key. Encrypts a message with a recipient's public key and a sender's secret key.
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key. - Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key. - Parameter senderSecretKey: The sender's secret key.
- Returns: A `Data` object containing the nonce and authenticated ciphertext. - Returns: A `Data` object containing the nonce and authenticated ciphertext.
*/ */
public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> Data? { public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> Data? {
@ -110,56 +106,53 @@ public class Box {
} }
var nonceAndAuthenticatedCipherText = nonce var nonceAndAuthenticatedCipherText = nonce
nonceAndAuthenticatedCipherText.append(authenticatedCipherText) nonceAndAuthenticatedCipherText.append(authenticatedCipherText)
return nonceAndAuthenticatedCipherText return nonceAndAuthenticatedCipherText
} }
/** /**
Encrypts a message with a recipient's public key and a sender's secret key using a user-provided nonce. 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 message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key. - Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key. - Parameter senderSecretKey: The sender's secret key.
- Paramter nonce: The user-specified nonce. - Parameter nonce: The user-specified nonce.
- Returns: The authenticated ciphertext. - Returns: The authenticated ciphertext.
*/ */
public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey, nonce: Nonce) -> Data? { public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey, nonce: Nonce) -> Data? {
guard recipientPublicKey.count == PublicKeyBytes, senderSecretKey.count == SecretKeyBytes, nonce.count == NonceBytes else { return nil } guard recipientPublicKey.count == PublicKeyBytes, senderSecretKey.count == SecretKeyBytes, nonce.count == NonceBytes else { return nil }
var authenticatedCipherText = Data(count: message.count + MacBytes) var authenticatedCipherText = Data(count: message.count + MacBytes)
let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in
return senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in
return crypto_box_easy( crypto_box_easy(
authenticatedCipherTextPtr, authenticatedCipherTextPtr,
messagePtr, messagePtr, CUnsignedLongLong(message.count),
CUnsignedLongLong(message.count),
noncePtr, noncePtr,
recipientPublicKeyPtr, recipientPublicKeyPtr, senderSecretKeyPtr)
senderSecretKeyPtr)
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return authenticatedCipherText return authenticatedCipherText
} }
/** /**
Encrypts a message with a recipient's public key and a sender's secret key. Encrypts a message with a recipient's public key and a sender's secret key.
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key. - Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key. - Parameter senderSecretKey: The sender's secret key.
- Returns: The authenticated ciphertext and encryption nonce. - Returns: The authenticated ciphertext and encryption nonce.
*/ */
public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> (authenticatedCipherText: Data, nonce: Nonce)? { public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> (authenticatedCipherText: Data, nonce: Nonce)? {
@ -168,39 +161,35 @@ public class Box {
} }
var authenticatedCipherText = Data(count: message.count + MacBytes) var authenticatedCipherText = Data(count: message.count + MacBytes)
let nonce = self.nonce() let nonce = self.nonce()
let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in
return senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in
return crypto_box_easy( crypto_box_easy(
authenticatedCipherTextPtr, authenticatedCipherTextPtr,
messagePtr, messagePtr, CUnsignedLongLong(message.count),
CUnsignedLongLong(message.count),
noncePtr, noncePtr,
recipientPublicKeyPtr, recipientPublicKeyPtr, senderSecretKeyPtr)
senderSecretKeyPtr)
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce) return (authenticatedCipherText: authenticatedCipherText, nonce: nonce)
} }
/** /**
Encrypts a message with a recipient's public key and a sender's secret key (detached mode). Encrypts a message with a recipient's public key and a sender's secret key (detached mode).
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key. - Parameter recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key. - Parameter senderSecretKey: The sender's secret key.
- Returns: The authenticated ciphertext, encryption nonce, and authentication tag. - Returns: The authenticated ciphertext, encryption nonce, and authentication tag.
*/ */
public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> (authenticatedCipherText: Data, nonce: Nonce, mac: MAC)? { public func seal(message: Data, recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> (authenticatedCipherText: Data, nonce: Nonce, mac: MAC)? {
@ -211,40 +200,35 @@ public class Box {
var mac = Data(count: MacBytes) var mac = Data(count: MacBytes)
let nonce = self.nonce() let nonce = self.nonce()
let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in
return mac.withUnsafeMutableBytes { macPtr in mac.withUnsafeMutableBytes { macPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in
return senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in
return crypto_box_detached( crypto_box_detached(
authenticatedCipherTextPtr, authenticatedCipherTextPtr, macPtr,
macPtr, messagePtr, CUnsignedLongLong(message.count),
messagePtr,
CUnsignedLongLong(message.count),
noncePtr, noncePtr,
recipientPublicKeyPtr, recipientPublicKeyPtr, senderSecretKeyPtr)
senderSecretKeyPtr)
} }
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce as Nonce, mac: mac as MAC) 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. Decrypts a message with a sender's public key and the recipient's secret key.
- Parameter nonceAndAuthenticatedCipherText: A `Data` object containing the nonce and authenticated ciphertext. - Parameter nonceAndAuthenticatedCipherText: A `Data` object containing the nonce and authenticated ciphertext.
- Parameter senderPublicKey: The sender's public key. - Parameter senderPublicKey: The sender's public key.
- Parameter recipientSecretKey: The recipient's secret key. - Parameter recipientSecretKey: The recipient's secret key.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(nonceAndAuthenticatedCipherText: Data, senderPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Data? { public func open(nonceAndAuthenticatedCipherText: Data, senderPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Data? {
@ -253,63 +237,58 @@ public class Box {
} }
let nonce = nonceAndAuthenticatedCipherText.subdata(in: 0..<NonceBytes) as Nonce let nonce = nonceAndAuthenticatedCipherText.subdata(in: 0..<NonceBytes) as Nonce
let authenticatedCipherText = nonceAndAuthenticatedCipherText.subdata(in: NonceBytes..<nonceAndAuthenticatedCipherText.count) let authenticatedCipherText = nonceAndAuthenticatedCipherText.subdata(in: NonceBytes..<nonceAndAuthenticatedCipherText.count)
return open(authenticatedCipherText: authenticatedCipherText, senderPublicKey: senderPublicKey, recipientSecretKey: recipientSecretKey, nonce: nonce) 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. Decrypts a message with a sender's public key, recipient's secret key, and encryption nonce.
- Parameter authenticatedCipherText: The authenticated ciphertext. - Parameter authenticatedCipherText: The authenticated ciphertext.
- Parameter senderPublicKey: The sender's public key. - Parameter senderPublicKey: The sender's public key.
- Parameter recipientSecretKey: The recipient's secret key. - Parameter recipientSecretKey: The recipient's secret key.
- Parameter nonce: The encryption nonce. - Parameter nonce: The encryption nonce.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(authenticatedCipherText: Data, senderPublicKey: PublicKey, recipientSecretKey: SecretKey, nonce: Nonce) -> Data? { public func open(authenticatedCipherText: Data, senderPublicKey: PublicKey, recipientSecretKey: SecretKey, nonce: Nonce) -> Data? {
if nonce.count != NonceBytes || authenticatedCipherText.count < MacBytes { if nonce.count != NonceBytes || authenticatedCipherText.count < MacBytes {
return nil return nil
} }
if senderPublicKey.count != PublicKeyBytes || recipientSecretKey.count != SecretKeyBytes { if senderPublicKey.count != PublicKeyBytes || recipientSecretKey.count != SecretKeyBytes {
return nil return nil
} }
var message = Data(count: authenticatedCipherText.count - MacBytes) var message = Data(count: authenticatedCipherText.count - MacBytes)
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return senderPublicKey.withUnsafeBytes { senderPublicKeyPtr in senderPublicKey.withUnsafeBytes { senderPublicKeyPtr in
return recipientSecretKey.withUnsafeBytes { recipientSecretKeyPtr in recipientSecretKey.withUnsafeBytes { recipientSecretKeyPtr in
return crypto_box_open_easy( crypto_box_open_easy(
messagePtr, messagePtr, authenticatedCipherTextPtr,
authenticatedCipherTextPtr,
CUnsignedLongLong(authenticatedCipherText.count), CUnsignedLongLong(authenticatedCipherText.count),
noncePtr, noncePtr,
senderPublicKeyPtr, senderPublicKeyPtr, recipientSecretKeyPtr)
recipientSecretKeyPtr)
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message return message
} }
/** /**
Decrypts a message with a sender's public key, recipient's secret key, encryption nonce, and authentication tag. Decrypts a message with a sender's public key, recipient's secret key, encryption nonce, and authentication tag.
- Parameter authenticatedCipherText: The authenticated ciphertext. - Parameter authenticatedCipherText: The authenticated ciphertext.
- Parameter senderPublicKey: The sender's public key. - Parameter senderPublicKey: The sender's public key.
- Parameter recipientSecretKey: The recipient's secret key. - Parameter recipientSecretKey: The recipient's secret key.
- Parameter nonce: The encryption nonce. - Parameter nonce: The encryption nonce.
- Parameter mac: The authentication tag. - Parameter mac: The authentication tag.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(authenticatedCipherText: Data, senderPublicKey: PublicKey, recipientSecretKey: SecretKey, nonce: Nonce, mac: MAC) -> Data? { public func open(authenticatedCipherText: Data, senderPublicKey: PublicKey, recipientSecretKey: SecretKey, nonce: Nonce, mac: MAC) -> Data? {
@ -320,83 +299,75 @@ public class Box {
return nil return nil
} }
var message = Data(count: authenticatedCipherText.count) var message = Data(count: authenticatedCipherText.count)
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in
return mac.withUnsafeBytes { macPtr in mac.withUnsafeBytes { macPtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return senderPublicKey.withUnsafeBytes { senderPublicKeyPtr in senderPublicKey.withUnsafeBytes { senderPublicKeyPtr in
return recipientSecretKey.withUnsafeBytes { recipientSecretKeyPtr in recipientSecretKey.withUnsafeBytes { recipientSecretKeyPtr in
return crypto_box_open_detached( crypto_box_open_detached(
messagePtr, messagePtr, authenticatedCipherTextPtr, macPtr,
authenticatedCipherTextPtr,
macPtr,
CUnsignedLongLong(authenticatedCipherText.count), CUnsignedLongLong(authenticatedCipherText.count),
noncePtr, noncePtr,
senderPublicKeyPtr, senderPublicKeyPtr, recipientSecretKeyPtr)
recipientSecretKeyPtr)
} }
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message return message
} }
/** /**
Computes a shared secret key given a public key and a secret key. 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. 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 recipientPublicKey: The recipient's public key.
- Parameter senderSecretKey: The sender's secret key. - Parameter senderSecretKey: The sender's secret key.
- Returns: The computed shared secret key - Returns: The computed shared secret key.
*/ */
public func beforenm(recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> Data? { public func beforenm(recipientPublicKey: PublicKey, senderSecretKey: SecretKey) -> Data? {
var key = Data(count: BeforenmBytes) var key = Data(count: BeforenmBytes)
let result = key.withUnsafeMutableBytes { keyPtr in let result = key.withUnsafeMutableBytes { keyPtr in
return recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in
return senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in senderSecretKey.withUnsafeBytes { senderSecretKeyPtr in
return crypto_box_beforenm(keyPtr, recipientPublicKeyPtr, senderSecretKeyPtr) crypto_box_beforenm(keyPtr, recipientPublicKeyPtr, senderSecretKeyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return key 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()`. 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 message: The message to encrypt.
- Parameter beforenm: The shared secret key. - Parameter beforenm: The shared secret key.
- Returns: The authenticated ciphertext and encryption nonce. - Returns: The authenticated ciphertext and encryption nonce.
*/ */
public func seal(message: Data, beforenm: Beforenm) -> (authenticatedCipherText: Data, nonce: Nonce)? { public func seal(message: Data, beforenm: Beforenm) -> (authenticatedCipherText: Data, nonce: Nonce)? {
if beforenm.count != BeforenmBytes { if beforenm.count != BeforenmBytes {
return nil return nil
} }
var authenticatedCipherText = Data(count: message.count + MacBytes) var authenticatedCipherText = Data(count: message.count + MacBytes)
let nonce = self.nonce() let nonce = self.nonce()
let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return beforenm.withUnsafeBytes { beforenmPtr in beforenm.withUnsafeBytes { beforenmPtr in
return crypto_box_easy_afternm( crypto_box_easy_afternm(
authenticatedCipherTextPtr, authenticatedCipherTextPtr,
messagePtr, messagePtr,
CUnsignedLongLong(message.count), CUnsignedLongLong(message.count),
@ -406,158 +377,143 @@ public class Box {
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce) 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()`. 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 `Data` object containing the nonce and authenticated ciphertext. - Parameter nonceAndAuthenticatedCipherText: A `Data` object containing the nonce and authenticated ciphertext.
- Parameter beforenm: The shared secret key. - Parameter beforenm: The shared secret key.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(nonceAndAuthenticatedCipherText: Data, beforenm: Beforenm) -> Data? { public func open(nonceAndAuthenticatedCipherText: Data, beforenm: Beforenm) -> Data? {
if nonceAndAuthenticatedCipherText.count < NonceBytes + MacBytes { if nonceAndAuthenticatedCipherText.count < NonceBytes + MacBytes {
return nil return nil
} }
let nonce = nonceAndAuthenticatedCipherText.subdata(in: 0..<NonceBytes) as Nonce let nonce = nonceAndAuthenticatedCipherText.subdata(in: 0..<NonceBytes) as Nonce
let authenticatedCipherText = nonceAndAuthenticatedCipherText.subdata(in: NonceBytes..<nonceAndAuthenticatedCipherText.count) let authenticatedCipherText = nonceAndAuthenticatedCipherText.subdata(in: NonceBytes..<nonceAndAuthenticatedCipherText.count)
return open(authenticatedCipherText: authenticatedCipherText, beforenm: beforenm, nonce: nonce) 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()`. 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 authenticatedCipherText: The authenticated ciphertext.
- Parameter beforenm: The shared secret key. - Parameter beforenm: The shared secret key.
- Parameter nonce: The encryption nonce. - Parameter nonce: The encryption nonce.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(authenticatedCipherText: Data, beforenm: Beforenm, nonce: Nonce) -> Data? { public func open(authenticatedCipherText: Data, beforenm: Beforenm, nonce: Nonce) -> Data? {
if nonce.count != NonceBytes || authenticatedCipherText.count < MacBytes { if nonce.count != NonceBytes || authenticatedCipherText.count < MacBytes {
return nil return nil
} }
if beforenm.count != BeforenmBytes { if beforenm.count != BeforenmBytes {
return nil return nil
} }
var message = Data(count: authenticatedCipherText.count - MacBytes) var message = Data(count: authenticatedCipherText.count - MacBytes)
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return beforenm.withUnsafeBytes { beforenmPtr in beforenm.withUnsafeBytes { beforenmPtr in
return crypto_box_open_easy_afternm( crypto_box_open_easy_afternm(
messagePtr, messagePtr,
authenticatedCipherTextPtr, authenticatedCipherTextPtr, CUnsignedLongLong(authenticatedCipherText.count),
CUnsignedLongLong(authenticatedCipherText.count), noncePtr, beforenmPtr)
noncePtr,
beforenmPtr)
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message 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()`. 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 message: The message to encrypt.
- Parameter beforenm: The shared secret key. - Parameter beforenm: The shared secret key.
- Returns: A `Data` object containing the encryption nonce and authenticated ciphertext. - Returns: A `Data` object containing the encryption nonce and authenticated ciphertext.
*/ */
public func seal(message: Data, beforenm: Beforenm) -> Data? { public func seal(message: Data, beforenm: Beforenm) -> Data? {
guard let (authenticatedCipherText, nonce): (Data, Nonce) = seal(message: message, beforenm: beforenm) else { guard let (authenticatedCipherText, nonce): (Data, Nonce) = seal(message: message, beforenm: beforenm) else {
return nil return nil
} }
var nonceAndAuthenticatedCipherText = nonce var nonceAndAuthenticatedCipherText = nonce
nonceAndAuthenticatedCipherText.append(authenticatedCipherText) nonceAndAuthenticatedCipherText.append(authenticatedCipherText)
return nonceAndAuthenticatedCipherText return nonceAndAuthenticatedCipherText
} }
/** /**
Encrypts a message with a recipient's public key. Encrypts a message with a recipient's public key.
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter recipientPublicKey: The recipient's public key. - Parameter recipientPublicKey: The recipient's public key.
- Returns: The anonymous ciphertext. - Returns: The anonymous ciphertext.
*/ */
public func seal(message: Data, recipientPublicKey: Box.PublicKey) -> Data? { public func seal(message: Data, recipientPublicKey: Box.PublicKey) -> Data? {
if recipientPublicKey.count != PublicKeyBytes { if recipientPublicKey.count != PublicKeyBytes {
return nil return nil
} }
var anonymousCipherText = Data(count: SealBytes + message.count) var anonymousCipherText = Data(count: SealBytes + message.count)
let result = anonymousCipherText.withUnsafeMutableBytes { anonymousCipherTextPtr in let result = anonymousCipherText.withUnsafeMutableBytes { anonymousCipherTextPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in
return crypto_box_seal( crypto_box_seal(
anonymousCipherTextPtr, anonymousCipherTextPtr,
messagePtr, messagePtr, CUnsignedLongLong(message.count),
CUnsignedLongLong(message.count),
recipientPublicKeyPtr) recipientPublicKeyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return anonymousCipherText return anonymousCipherText
} }
/** /**
Decrypts a message with the recipient's public key and secret key. Decrypts a message with the recipient's public key and secret key.
- Parameter anonymousCipherText: A `Data` object containing the anonymous ciphertext. - Parameter anonymousCipherText: A `Data` object containing the anonymous ciphertext.
- Parameter senderPublicKey: The recipient's public key. - Parameter senderPublicKey: The recipient's public key.
- Parameter recipientSecretKey: The recipient's secret key. - Parameter recipientSecretKey: The recipient's secret key.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(anonymousCipherText: Data, recipientPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Data? { public func open(anonymousCipherText: Data, recipientPublicKey: PublicKey, recipientSecretKey: SecretKey) -> Data? {
if recipientPublicKey.count != PublicKeyBytes || recipientSecretKey.count != SecretKeyBytes || anonymousCipherText.count < SealBytes { if recipientPublicKey.count != PublicKeyBytes || recipientSecretKey.count != SecretKeyBytes || anonymousCipherText.count < SealBytes {
return nil return nil
} }
var message = Data(count: anonymousCipherText.count - SealBytes) var message = Data(count: anonymousCipherText.count - SealBytes)
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return anonymousCipherText.withUnsafeBytes { anonymousCipherTextPtr in anonymousCipherText.withUnsafeBytes { anonymousCipherTextPtr in
return recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in recipientPublicKey.withUnsafeBytes { recipientPublicKeyPtr in
return recipientSecretKey.withUnsafeBytes { recipientSecretKeyPtr in recipientSecretKey.withUnsafeBytes { recipientSecretKeyPtr in
return crypto_box_seal_open( crypto_box_seal_open(
messagePtr, messagePtr,
anonymousCipherTextPtr, anonymousCipherTextPtr, CUnsignedLongLong(anonymousCipherText.count),
CUnsignedLongLong(anonymousCipherText.count), recipientPublicKeyPtr, recipientSecretKeyPtr)
recipientPublicKeyPtr,
recipientSecretKeyPtr)
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message return message
} }
} }

View File

@ -2,9 +2,6 @@
// GenericHash.swift // GenericHash.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/27/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -17,12 +14,12 @@ public class GenericHash {
public let KeyBytesMax = Int(crypto_generichash_keybytes_max()) public let KeyBytesMax = Int(crypto_generichash_keybytes_max())
public let KeyBytes = Int(crypto_generichash_keybytes()) public let KeyBytes = Int(crypto_generichash_keybytes())
public let Primitive = String.init(validatingUTF8: crypto_generichash_primitive()) public let Primitive = String.init(validatingUTF8: crypto_generichash_primitive())
public typealias Key = Data public typealias Key = Data
/** /**
Generates a secret key. Generates a secret key.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> Key? { public func key() -> Key? {
@ -32,126 +29,116 @@ public class GenericHash {
} }
return k return k
} }
/** /**
Computes a fixed-length fingerprint for an arbitrary long message. A key can also be specified. A message will always have the same fingerprint for a given key, but different keys used to hash the same message are very likely to produce distinct fingerprints. Computes a fixed-length fingerprint for an arbitrary long message. A key can also be specified. A message will always have the same fingerprint for a given key, but different keys used to hash the same message are very likely to produce distinct fingerprints.
- Parameter message: The message from which to compute the fingerprint. - Parameter message: The message from which to compute the fingerprint.
- Parameter key: Optional key to use while computing the fingerprint. - Parameter key: Optional key to use while computing the fingerprint.
- Returns: The computed fingerprint. - Returns: The computed fingerprint.
*/ */
public func hash(message: Data, key: Data? = nil) -> Data? { public func hash(message: Data, key: Data? = nil) -> Data? {
return hash(message: message, key: key, outputLength: Bytes) return hash(message: message, key: key, outputLength: Bytes)
} }
/** /**
Computes a fixed-length fingerprint for an arbitrary long message. A message will always have the same fingerprint for a given key, but different keys used to hash the same message are very likely to produce distinct fingerprints. Computes a fixed-length fingerprint for an arbitrary long message. A message will always have the same fingerprint for a given key, but different keys used to hash the same message are very likely to produce distinct fingerprints.
- Parameter message: The message from which to compute the fingerprint. - Parameter message: The message from which to compute the fingerprint.
- Parameter key: The key to use while computing the fingerprint. - Parameter key: The key to use while computing the fingerprint.
- Parameter outputLength: Desired length of the computed fingerprint. - Parameter outputLength: Desired length of the computed fingerprint.
- Returns: The computed fingerprint. - Returns: The computed fingerprint.
*/ */
public func hash(message: Data, key: Data?, outputLength: Int) -> Data? { public func hash(message: Data, key: Data?, outputLength: Int) -> Data? {
var output = Data(count: outputLength) var output = Data(count: outputLength)
var result: Int32 = -1 var result: Int32 = -1
if let key = key { if let key = key {
result = output.withUnsafeMutableBytes { outputPtr in result = output.withUnsafeMutableBytes { outputPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return key.withUnsafeBytes { keyPtr in key.withUnsafeBytes { keyPtr in
return crypto_generichash( crypto_generichash(
outputPtr, outputPtr, output.count,
output.count, messagePtr, CUnsignedLongLong(message.count),
messagePtr, keyPtr, key.count)
CUnsignedLongLong(message.count),
keyPtr,
key.count)
} }
} }
} }
} else { } else {
result = output.withUnsafeMutableBytes { outputPtr in result = output.withUnsafeMutableBytes { outputPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return crypto_generichash( crypto_generichash(
outputPtr, outputPtr, output.count,
output.count, messagePtr, CUnsignedLongLong(message.count),
messagePtr, nil, 0)
CUnsignedLongLong(message.count),
nil,
0)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return output return output
} }
/** /**
Computes a fixed-length fingerprint for an arbitrary long message. Computes a fixed-length fingerprint for an arbitrary long message.
- Parameter message: The message from which to compute the fingerprint. - Parameter message: The message from which to compute the fingerprint.
- Parameter outputLength: Desired length of the computed fingerprint. - Parameter outputLength: Desired length of the computed fingerprint.
- Returns: The computed fingerprint. - Returns: The computed fingerprint.
*/ */
public func hash(message: Data, outputLength: Int) -> Data? { public func hash(message: Data, outputLength: Int) -> Data? {
return hash(message: message, key: nil, outputLength: outputLength) return hash(message: message, key: nil, outputLength: outputLength)
} }
/** /**
Initializes a `Stream` object to compute a fixed-length fingerprint for an incoming stream of data.arbitrary long message. Particular data will always have the same fingerprint for a given key, but different keys used to hash the same data are very likely to produce distinct fingerprints. Initializes a `Stream` object to compute a fixed-length fingerprint for an incoming stream of data.arbitrary long message. Particular data will always have the same fingerprint for a given key, but different keys used to hash the same data are very likely to produce distinct fingerprints.
- Parameter key: Optional key to use while computing the fingerprint. - Parameter key: Optional key to use while computing the fingerprint.
- Returns: The initialized `Stream`. - Returns: The initialized `Stream`.
*/ */
public func initStream(key: Data? = nil) -> Stream? { public func initStream(key: Data? = nil) -> Stream? {
return Stream(key: key, outputLength: Bytes) return Stream(key: key, outputLength: Bytes)
} }
/** /**
Initializes a `Stream` object to compute a fixed-length fingerprint for an incoming stream of data.arbitrary long message. Particular data will always have the same fingerprint for a given key, but different keys used to hash the same data are very likely to produce distinct fingerprints. Initializes a `Stream` object to compute a fixed-length fingerprint for an incoming stream of data.arbitrary long message. Particular data will always have the same fingerprint for a given key, but different keys used to hash the same data are very likely to produce distinct fingerprints.
- Parameter key: Optional key to use while computing the fingerprint. - Parameter key: Optional key to use while computing the fingerprint.
- Parameter outputLength: Desired length of the computed fingerprint. - Parameter outputLength: Desired length of the computed fingerprint.
- Returns: The initialized `Stream`. - Returns: The initialized `Stream`.
*/ */
public func initStream(key: Data?, outputLength: Int) -> Stream? { public func initStream(key: Data?, outputLength: Int) -> Stream? {
return Stream(key: key, outputLength: outputLength) return Stream(key: key, outputLength: outputLength)
} }
/** /**
Initializes a `Stream` object to compute a fixed-length fingerprint for an incoming stream of data.arbitrary long message. Initializes a `Stream` object to compute a fixed-length fingerprint for an incoming stream of data.arbitrary long message.
- Parameter: outputLength: Desired length of the computed fingerprint. - Parameter: outputLength: Desired length of the computed fingerprint.
- Returns: The initialized `Stream`. - Returns: The initialized `Stream`.
*/ */
public func initStream(outputLength: Int) -> Stream? { public func initStream(outputLength: Int) -> Stream? {
return Stream(key: nil, outputLength: outputLength) return Stream(key: nil, outputLength: outputLength)
} }
public class Stream { public class Stream {
public var outputLength: Int = 0 public var outputLength: Int = 0
private var state: UnsafeMutablePointer<crypto_generichash_state>? private var state: UnsafeMutablePointer<crypto_generichash_state>?
init?(key: Data?, outputLength: Int) { init?(key: Data?, outputLength: Int) {
let rawState = UnsafeMutablePointer<UInt8>.allocate(capacity: crypto_generichash_statebytes()) let rawState = UnsafeMutablePointer<UInt8>.allocate(capacity: crypto_generichash_statebytes())
state = UnsafeMutableRawPointer(rawState).bindMemory(to: crypto_generichash_state.self, capacity: 1) state = UnsafeMutableRawPointer(rawState).bindMemory(to: crypto_generichash_state.self, capacity: 1)
guard let state = state else { guard let state = state else {
return nil return nil
} }
var result: Int32 = -1 var result: Int32 = -1
if let key = key { if let key = key {
result = key.withUnsafeBytes { keyPtr in result = key.withUnsafeBytes { keyPtr in
crypto_generichash_init(state, keyPtr, key.count, outputLength) crypto_generichash_init(state, keyPtr, key.count, outputLength)
@ -159,14 +146,12 @@ public class GenericHash {
} else { } else {
result = crypto_generichash_init(state, nil, 0, outputLength) result = crypto_generichash_init(state, nil, 0, outputLength)
} }
if result != 0 { if result != 0 {
return nil return nil
} }
self.outputLength = outputLength self.outputLength = outputLength
} }
deinit { deinit {
guard let state = state else { guard let state = state else {
return return
@ -174,23 +159,23 @@ public class GenericHash {
let rawState = UnsafeMutableRawPointer(state).bindMemory(to: UInt8.self, capacity: crypto_generichash_statebytes()) let rawState = UnsafeMutableRawPointer(state).bindMemory(to: UInt8.self, capacity: crypto_generichash_statebytes())
rawState.deallocate(capacity: 1) rawState.deallocate(capacity: 1)
} }
/** /**
Updates the hash stream with incoming data to contribute to the computed fingerprint. Updates the hash stream with incoming data to contribute to the computed fingerprint.
- Parameter input: The incoming stream data. - Parameter input: The incoming stream data.
- Returns: `true` if the data was consumed successfully. - Returns: `true` if the data was consumed successfully.
*/ */
public func update(input: Data) -> Bool { public func update(input: Data) -> Bool {
return input.withUnsafeBytes { inputPtr in return input.withUnsafeBytes { inputPtr in
return crypto_generichash_update(state!, inputPtr, CUnsignedLongLong(input.count)) == 0 crypto_generichash_update(state!, inputPtr, CUnsignedLongLong(input.count)) == 0
} }
} }
/** /**
Signals that the incoming stream of data is complete and triggers computation of the resulting fingerprint. Signals that the incoming stream of data is complete and triggers computation of the resulting fingerprint.
- Returns: The computed fingerprint. - Returns: The computed fingerprint.
*/ */
public func final() -> Data? { public func final() -> Data? {
@ -198,11 +183,9 @@ public class GenericHash {
let result = output.withUnsafeMutableBytes { outputPtr in let result = output.withUnsafeMutableBytes { outputPtr in
crypto_generichash_final(state!, outputPtr, output.count) crypto_generichash_final(state!, outputPtr, output.count)
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return output return output
} }
} }

View File

@ -2,9 +2,6 @@
// KeyDerivation.swift // KeyDerivation.swift
// Sodium // Sodium
// //
// Created by Patrick Salami (https://www.github.com/psalami) on 7/7/17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -14,13 +11,13 @@ public class KeyDerivation {
public let BytesMax = Int(crypto_kdf_bytes_max()) public let BytesMax = Int(crypto_kdf_bytes_max())
public let KeyBytes = Int(crypto_kdf_keybytes()) public let KeyBytes = Int(crypto_kdf_keybytes())
public let ContextBytes = Int(crypto_kdf_contextbytes()) public let ContextBytes = Int(crypto_kdf_contextbytes())
public typealias Key = Data public typealias Key = Data
public typealias SubKey = Data public typealias SubKey = Data
/** /**
Generates a secret key. Generates a secret key.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> Key? { public func key() -> Key? {
@ -30,17 +27,18 @@ public class KeyDerivation {
} }
return k return k
} }
/** /**
Derives a subkey from the specified input key. Each index (from 0 to (2^64) - 1) yields a unique deterministic subkey. Derives a subkey from the specified input key. Each index (from 0 to (2^64) - 1) yields a unique deterministic subkey.
The sequence of subkeys is likely unique for a given context. The sequence of subkeys is likely unique for a given context.
- Parameter secretKey: the master key from which to derive the subkey (must be KeyBytes bytes) - Parameter secretKey: the master key from which to derive the subkey (must be KeyBytes bytes)
- Parameter index: the index of the subkey to generate (allowed range: 0 to (2^64) - 1) - Parameter index: the index of the subkey to generate (allowed range: 0 to (2^64) - 1)
- Parameter length: the desired length of the subkey in bytes (allowed range: BytesMin to BytesMax) - Parameter length: the desired length of the subkey in bytes (allowed range: BytesMin to BytesMax)
- Parameter context: a String that identifies the context; use a different value for different types of keys (should be exactly 8 characters long but must be no longer than 8 characters) - Parameter context: a String that identifies the context; use a different value for different types of keys (should be exactly 8 characters long but must be no longer than 8 characters)
- Returns: the derived key or nil on error. - Returns: the derived key or nil on error.
- Note: Output keys must have a length between BytesMin and BytesMax bytes (inclusive), otherwise an error is returned. Context must be at most 8 characters long. If the specified context is shorter than 8 characters, it will be padded to 8 characters. The master key is KeyBytes long. - Note: Output keys must have a length between BytesMin and BytesMax bytes (inclusive), otherwise an error is returned. Context must be at most 8 characters long. If the specified context is shorter than 8 characters, it will be padded to 8 characters. The master key is KeyBytes long.
*/ */
public func derive(secretKey: Data, index: UInt64, length: Int, context: String) -> Data? { public func derive(secretKey: Data, index: UInt64, length: Int, context: String) -> Data? {
@ -54,17 +52,16 @@ public class KeyDerivation {
if contextBin.count > ContextBytes { if contextBin.count > ContextBytes {
return nil return nil
} }
while contextBin.count < ContextBytes { while contextBin.count < ContextBytes {
contextBin += [0] contextBin += [0]
} }
var output = Data(count: length) var output = Data(count: length)
let result = output.withUnsafeMutableBytes { outputPtr in let result = output.withUnsafeMutableBytes { outputPtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return contextBin.withUnsafeBytes { contextBinPtr in contextBin.withUnsafeBytes { contextBinPtr in
return crypto_kdf_derive_from_key(outputPtr, length, index, contextBinPtr, secretKeyPtr) crypto_kdf_derive_from_key(outputPtr, length, index, contextBinPtr, secretKeyPtr)
} }
} }
} }

View File

@ -2,145 +2,130 @@
// KeyExchange.swift // KeyExchange.swift
// Sodium // Sodium
// //
// Created by Andreas Ganske on 17.03.17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
public class KeyExchange { public class KeyExchange {
public let PublicKeyBytes = Int(crypto_kx_publickeybytes()) public let PublicKeyBytes = Int(crypto_kx_publickeybytes())
public let SecretKeyBytes = Int(crypto_kx_secretkeybytes()) public let SecretKeyBytes = Int(crypto_kx_secretkeybytes())
public let SessionKeyBytes = Int(crypto_kx_sessionkeybytes()) public let SessionKeyBytes = Int(crypto_kx_sessionkeybytes())
public let SeedBytes = Int(crypto_kx_seedbytes()) public let SeedBytes = Int(crypto_kx_seedbytes())
public typealias PublicKey = Data public typealias PublicKey = Data
public typealias SecretKey = Data public typealias SecretKey = Data
public struct KeyPair { public struct KeyPair {
public let publicKey: PublicKey public let publicKey: PublicKey
public let secretKey: SecretKey public let secretKey: SecretKey
public init(publicKey: PublicKey, secretKey: SecretKey) { public init(publicKey: PublicKey, secretKey: SecretKey) {
self.publicKey = publicKey self.publicKey = publicKey
self.secretKey = secretKey self.secretKey = secretKey
} }
} }
public struct SessionKeyPair { public struct SessionKeyPair {
public let rx: Data public let rx: Data
public let tx: Data public let tx: Data
public init(rx: Data, tx: Data) { public init(rx: Data, tx: Data) {
self.rx = rx self.rx = rx
self.tx = tx self.tx = tx
} }
} }
public enum Side { public enum Side {
case client case CLIENT
case server case SERVER
} }
/** /**
Generates a key exchange secret key and a corresponding public key. Generates a key exchange secret key and a corresponding public key.
- Returns: A key pair containing the secret key and public key. - Returns: A key pair containing the secret key and public key.
*/ */
public func keyPair() -> KeyPair? { public func keyPair() -> KeyPair? {
var publicKey = Data(count: PublicKeyBytes) var publicKey = Data(count: PublicKeyBytes)
var secretKey = Data(count: SecretKeyBytes) var secretKey = Data(count: SecretKeyBytes)
var result: Int32 = -1 let result = publicKey.withUnsafeMutableBytes { publicKeyPtr in
result = publicKey.withUnsafeMutableBytes { publicKeyPtr in secretKey.withUnsafeMutableBytes { secretKeyPtr in
return secretKey.withUnsafeMutableBytes { secretKeyPtr in crypto_kx_keypair(publicKeyPtr, secretKeyPtr)
return crypto_kx_keypair(publicKeyPtr, secretKeyPtr)
} }
} }
guard result == 0 else { guard result == 0 else {
return nil return nil
} }
return KeyPair(publicKey: publicKey, secretKey: secretKey) return KeyPair(publicKey: publicKey, secretKey: secretKey)
} }
/** /**
Generates a key exchange secret key and a corresponding public key derived from a seed. Generates a key exchange secret key and a corresponding public key derived from a seed.
- Parameter seed: The value from which to derive the secret and public key. - Parameter seed: The value from which to derive the secret and public key.
- Returns: A key pair containing the secret key and public key. - Returns: A key pair containing the secret key and public key.
*/ */
public func keyPair(seed: Data) -> KeyPair? { public func keyPair(seed: Data) -> KeyPair? {
if seed.count != SeedBytes { if seed.count != SeedBytes {
return nil return nil
} }
var pk = Data(count: PublicKeyBytes) var pk = Data(count: PublicKeyBytes)
var sk = Data(count: SecretKeyBytes) var sk = Data(count: SecretKeyBytes)
let result = pk.withUnsafeMutableBytes { pkPtr in let result = pk.withUnsafeMutableBytes { pkPtr in
return sk.withUnsafeMutableBytes { skPtr in sk.withUnsafeMutableBytes { skPtr in
return seed.withUnsafeBytes { seedPtr in seed.withUnsafeBytes { seedPtr in
return crypto_kx_seed_keypair(pkPtr, skPtr, seedPtr) crypto_kx_seed_keypair(pkPtr, skPtr, seedPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return KeyPair(publicKey: pk, secretKey: sk) return KeyPair(publicKey: pk, secretKey: sk)
} }
/** /**
Using this function, two parties can securely compute a set of shared keys using their peer's public key and their own secret key. Using this function, two parties can securely compute a set of shared keys using their peer's public key and their own secret key.
See [libsodium.org/doc/key_exchange](https://download.libsodium.org/doc/key_exchange) for more details. See [libsodium.org/doc/key_exchange](https://download.libsodium.org/doc/key_exchange) for more details.
- Parameter publicKey: The public key used for the key exchange - Parameter publicKey: The public key used for the key exchange
- Parameter secretKey: The secret key to used for the key exchange - Parameter secretKey: The secret key to used for the key exchange
- Parameter otherPublicKey: The peer's public key for the key exchange - Parameter otherPublicKey: The peer's public key for the key exchange
- Parameter side: Side (`client` or `host`) on which the key exchange is run - Parameter side: Side (`client` or `host`) on which the key exchange is run
- Returns: A `SessionKeyPair` consisting of a receive (`rx`) key and a transmit (`tx`) key - Returns: A `SessionKeyPair` consisting of a receive (`rx`) key and a transmit (`tx`) key
- Note: `rx` on client side equals `tx` on server side and vice versa. - Note: `rx` on client side equals `tx` on server side and vice versa.
*/ */
public func sessionKeyPair(publicKey: PublicKey, secretKey: SecretKey, otherPublicKey: PublicKey, side: Side) -> SessionKeyPair? { public func sessionKeyPair(publicKey: PublicKey, secretKey: SecretKey, otherPublicKey: PublicKey, side: Side) -> SessionKeyPair? {
if publicKey.count != PublicKeyBytes || if publicKey.count != PublicKeyBytes ||
secretKey.count != SecretKeyBytes || secretKey.count != SecretKeyBytes ||
otherPublicKey.count != PublicKeyBytes { otherPublicKey.count != PublicKeyBytes {
return nil return nil
} }
var rx = Data(count: SessionKeyBytes) var rx = Data(count: SessionKeyBytes)
var tx = Data(count: SessionKeyBytes) var tx = Data(count: SessionKeyBytes)
let session_keys = (side == .client) ? crypto_kx_client_session_keys : crypto_kx_server_session_keys let session_keys = (side == .CLIENT) ? crypto_kx_client_session_keys : crypto_kx_server_session_keys
let result = rx.withUnsafeMutableBytes { rxPtr in let result = rx.withUnsafeMutableBytes { rxPtr in
return tx.withUnsafeMutableBytes { txPtr in tx.withUnsafeMutableBytes { txPtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return publicKey.withUnsafeBytes { publicKeyPtr in publicKey.withUnsafeBytes { publicKeyPtr in
return otherPublicKey.withUnsafeBytes { otherPublicKeyPtr in otherPublicKey.withUnsafeBytes { otherPublicKeyPtr in
return session_keys(rxPtr, txPtr, publicKeyPtr, secretKeyPtr, otherPublicKeyPtr) session_keys(rxPtr, txPtr, publicKeyPtr, secretKeyPtr, otherPublicKeyPtr)
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return SessionKeyPair(rx: rx, tx: tx) return SessionKeyPair(rx: rx, tx: tx)
} }
} }

View File

@ -2,9 +2,6 @@
// PWHash.swift // PWHash.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 4/29/15.
// Copyright (c) 2015 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -19,77 +16,70 @@ public class PWHash {
public let MemLimitInteractive = Int(crypto_pwhash_memlimit_interactive()) public let MemLimitInteractive = Int(crypto_pwhash_memlimit_interactive())
public let MemLimitModerate = Int(crypto_pwhash_memlimit_moderate()) public let MemLimitModerate = Int(crypto_pwhash_memlimit_moderate())
public let MemLimitSensitive = Int(crypto_pwhash_memlimit_sensitive()) public let MemLimitSensitive = Int(crypto_pwhash_memlimit_sensitive())
public enum Alg { public enum Alg {
case Default case Default
case Argon2I13 case Argon2I13
case Argon2ID13 case Argon2ID13
} }
/** /**
Generates an ASCII encoded string, which includes: Generates an ASCII encoded string, which includes:
- the result of the memory-hard, CPU-intensive Argon2 password hashing function applied to the password `passwd` - the result of the memory-hard, CPU-intensive Argon2 password hashing function applied to the password `passwd`
- the automatically generated salt used for the previous computation - the automatically generated salt used for the previous computation
- the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit. - the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit.
The output string includes only ASCII characters and can be safely stored into SQL databases and other data stores. No extra information has to be stored in order to verify the password. The output string includes only ASCII characters and can be safely stored into SQL databases and other data stores. No extra information has to be stored in order to verify the password.
- Parameter passwd: The password data to hash. - Parameter passwd: The password data to hash.
- Parameter opsLimit: Represents a maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key. - Parameter opsLimit: Represents a maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key.
- Parameter memLimit: The maximum amount of RAM that the function will use, in bytes. - Parameter memLimit: The maximum amount of RAM that the function will use, in bytes.
- Returns: The generated string. - Returns: The generated string.
*/ */
public func str(passwd: Data, opsLimit: Int, memLimit: Int) -> String? { public func str(passwd: Data, opsLimit: Int, memLimit: Int) -> String? {
var output = Data(count: StrBytes) var output = Data(count: StrBytes)
let result = output.withUnsafeMutableBytes { outputPtr in let result = output.withUnsafeMutableBytes { outputPtr in
return passwd.withUnsafeBytes { passwdPtr in passwd.withUnsafeBytes { passwdPtr in
return crypto_pwhash_str(outputPtr, crypto_pwhash_str(outputPtr,
passwdPtr, passwdPtr, CUnsignedLongLong(passwd.count),
CUnsignedLongLong(passwd.count), CUnsignedLongLong(opsLimit), size_t(memLimit))
CUnsignedLongLong(opsLimit),
size_t(memLimit))
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return String(data: output, encoding: .utf8) return String(data: output, encoding: .utf8)
} }
/** /**
Verifies that the password str is a valid password verification string (as generated by `str(passwd: Data, opslimit: Int, memLimit: Int)` for `passwd`. Verifies that the password str is a valid password verification string (as generated by `str(passwd: Data, opslimit: Int, memLimit: Int)` for `passwd`.
- Parameter hash: The password hash string to verify. - Parameter hash: The password hash string to verify.
- Parameter passwd: The password data to verify. - Parameter passwd: The password data to verify.
- Returns: `true` if the verification succeeds. - Returns: `true` if the verification succeeds.
*/ */
public func strVerify(hash: String, passwd: Data) -> Bool { public func strVerify(hash: String, passwd: Data) -> Bool {
guard let hashData = (hash + "\0").data(using: .utf8, allowLossyConversion: false) else { guard let hashData = (hash + "\0").data(using: .utf8, allowLossyConversion: false) else {
return false return false
} }
return hashData.withUnsafeBytes { hashPtr in return hashData.withUnsafeBytes { hashPtr in
return passwd.withUnsafeBytes { passwdPtr in passwd.withUnsafeBytes { passwdPtr in
return crypto_pwhash_str_verify( crypto_pwhash_str_verify(
hashPtr, hashPtr, passwdPtr, CUnsignedLongLong(passwd.count)) == 0
passwdPtr,
CUnsignedLongLong(passwd.count)) == 0
} }
} }
} }
/** /**
Check that a string previously hashed password matches the current algorithm and parameters Checks that a string previously hashed password matches the current algorithm and parameters
- Parameter hash: The password hash string to check. - Parameter hash: The password hash string to check.
- Parameter opsLimit: Represents a maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key. - Parameter opsLimit: Represents a maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key.
- Parameter memLimit: The maximum amount of RAM that the function will use, in bytes. - Parameter memLimit: The maximum amount of RAM that the function will use, in bytes.
- Returns: `true` if the password hash should be updated. - Returns: `true` if the password hash should be updated.
*/ */
public func strNeedsRehash(hash: String, opsLimit: Int, memLimit: Int) -> Bool { public func strNeedsRehash(hash: String, opsLimit: Int, memLimit: Int) -> Bool {
@ -97,31 +87,29 @@ public class PWHash {
return true return true
} }
return hashData.withUnsafeBytes { hashPtr in return hashData.withUnsafeBytes { hashPtr in
return crypto_pwhash_str_needs_rehash( crypto_pwhash_str_needs_rehash(
hashPtr, hashPtr, CUnsignedLongLong(opsLimit), size_t(memLimit)) != 0
CUnsignedLongLong(opsLimit), size_t(memLimit)) != 0
} }
} }
/** /**
Derives a key from a password and a salt using the Argon2 password hashing function. Derives a key from a password and a salt using the Argon2 password hashing function.
Keep in mind that in order to produce the same key from the same password, the same salt, and the same values for opslimit and memlimit have to be used. Therefore, these parameters have to be stored for each user. Keep in mind that in order to produce the same key from the same password, the same salt, and the same values for opslimit and memlimit have to be used. Therefore, these parameters have to be stored for each user.
- Parameter outputLength: Desired length of the derived key. Should be at least 16 (128 bits) - Parameter outputLength: Desired length of the derived key. Should be at least 16 (128 bits)
- Parameter passwd: The password data to hash. - Parameter passwd: The password data to hash.
- Parameter salt: Unpredicatable salt data. Must have a fixed length of `SaltBytes`. - Parameter salt: Unpredicatable salt data. Must have a fixed length of `SaltBytes`.
- Parameter opsLimit: Represents a maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key. - Parameter opsLimit: Represents a maximum amount of computations to perform. Raising this number will make the function require more CPU cycles to compute a key.
- Parameter memLimit: The maximum amount of RAM that the function will use, in bytes. - Parameter memLimit: The maximum amount of RAM that the function will use, in bytes.
- Parameter alg: The algorithm identifier (.Default, .Argon2I13, .Argon2ID13). - Parameter alg: The algorithm identifier (`.Default`, `.Argon2I13`, `.Argon2ID13`).
- Returns: The derived key data. - Returns: The derived key data.
*/ */
public func hash(outputLength: Int, passwd: Data, salt: Data, opsLimit: Int, memLimit: Int, alg: Alg = .Default) -> Data? { public func hash(outputLength: Int, passwd: Data, salt: Data, opsLimit: Int, memLimit: Int, alg: Alg = .Default) -> Data? {
if salt.count != SaltBytes { if salt.count != SaltBytes {
return nil return nil
} }
var output = Data(count: outputLength) var output = Data(count: outputLength)
var algId: Int32 var algId: Int32
switch alg { switch alg {
@ -133,9 +121,9 @@ public class PWHash {
algId = crypto_pwhash_alg_argon2id13() algId = crypto_pwhash_alg_argon2id13()
} }
let result = passwd.withUnsafeBytes { passwdPtr in let result = passwd.withUnsafeBytes { passwdPtr in
return salt.withUnsafeBytes { saltPtr in salt.withUnsafeBytes { saltPtr in
return output.withUnsafeMutableBytes { outputPtr in output.withUnsafeMutableBytes { outputPtr in
return crypto_pwhash( crypto_pwhash(
outputPtr, CUnsignedLongLong(outputLength), outputPtr, CUnsignedLongLong(outputLength),
passwdPtr, CUnsignedLongLong(passwd.count), passwdPtr, CUnsignedLongLong(passwd.count),
saltPtr, CUnsignedLongLong(opsLimit), saltPtr, CUnsignedLongLong(opsLimit),
@ -143,11 +131,9 @@ public class PWHash {
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return output return output
} }
} }

View File

@ -2,21 +2,18 @@
// RandomBytes.swift // RandomBytes.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/27/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
public class RandomBytes { public class RandomBytes {
public let SeedBytes = Int(randombytes_seedbytes()) public let SeedBytes = Int(randombytes_seedbytes())
/** /**
Returns a `Data object of length `length` containing an unpredictable sequence of bytes. Returns a `Data object of length `length` containing an unpredictable sequence of bytes.
- Parameter length: The number of bytes to generate. - Parameter length: The number of bytes to generate.
- Returns: The generated data. - Returns: The generated data.
*/ */
public func buf(length: Int) -> Data? { public func buf(length: Int) -> Data? {
@ -29,31 +26,31 @@ public class RandomBytes {
} }
return output return output
} }
/** /**
- Returns: An unpredictable value between 0 and 0xffffffff (included). - Returns: An unpredictable value between 0 and 0xffffffff (included).
*/ */
public func random() -> UInt32 { public func random() -> UInt32 {
return randombytes_random() return randombytes_random()
} }
/** /**
Returns an unpredictable value between 0 and `upper_bound` (excluded). Unlike randombytes_random() % upper_bound, it does its best to guarantee a uniform distribution of the possible output values even when upper_bound is not a power of 2. Returns an unpredictable value between 0 and `upper_bound` (excluded). Unlike randombytes_random() % upper_bound, it does its best to guarantee a uniform distribution of the possible output values even when upper_bound is not a power of 2.
- Parameter upperBound: The upper bound (excluded) of the returned value. - Parameter upperBound: The upper bound (excluded) of the returned value.
- Returns: The unpredictable value. - Returns: The unpredictable value.
*/ */
public func uniform(upperBound: UInt32) -> UInt32 { public func uniform(upperBound: UInt32) -> UInt32 {
return randombytes_uniform(upperBound) return randombytes_uniform(upperBound)
} }
/** /**
Returns a deterministic stream of unbiased bits derived from a seed. Returns a deterministic stream of unbiased bits derived from a seed.
- Parameter length: The number of bytes to generate. - Parameter length: The number of bytes to generate.
- Parameter seed: The seed. - Parameter seed: The seed.
- Returns: The generated data. - Returns: The generated data.
*/ */
public func deterministic(length: Int, seed: Data) -> Data? { public func deterministic(length: Int, seed: Data) -> Data? {
@ -62,7 +59,7 @@ public class RandomBytes {
} }
var output = Data(count: length) var output = Data(count: length)
output.withUnsafeMutableBytes { outputPtr in output.withUnsafeMutableBytes { outputPtr in
return seed.withUnsafeBytes { seedPtr in seed.withUnsafeBytes { seedPtr in
randombytes_buf_deterministic(outputPtr, output.count, seedPtr) randombytes_buf_deterministic(outputPtr, output.count, seedPtr)
} }
} }

View File

@ -2,9 +2,6 @@
// SecretBox.swift // SecretBox.swift
// Sodium // Sodium
// //
// Created by Devin Chalmers on 1/4/15.
// Copyright (c) 2015 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -13,14 +10,14 @@ public class SecretBox {
public let KeyBytes = Int(crypto_secretbox_keybytes()) public let KeyBytes = Int(crypto_secretbox_keybytes())
public let NonceBytes = Int(crypto_secretbox_noncebytes()) public let NonceBytes = Int(crypto_secretbox_noncebytes())
public let MacBytes = Int(crypto_secretbox_macbytes()) public let MacBytes = Int(crypto_secretbox_macbytes())
public typealias Key = Data public typealias Key = Data
public typealias Nonce = Data public typealias Nonce = Data
public typealias MAC = Data public typealias MAC = Data
/** /**
Generates a shared secret key. Generates a shared secret key.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> Key? { public func key() -> Key? {
@ -30,10 +27,10 @@ public class SecretBox {
} }
return k return k
} }
/** /**
Generates an encryption nonce. Generates an encryption nonce.
- Returns: The generated nonce. - Returns: The generated nonce.
*/ */
public func nonce() -> Nonce { public func nonce() -> Nonce {
@ -43,202 +40,180 @@ public class SecretBox {
} }
return nonce return nonce
} }
/** /**
Encrypts a message with a shared secret key. Encrypts a message with a shared secret key.
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter secretKey: The shared secret key. - Parameter secretKey: The shared secret key.
- Returns: A `Data` object containing the nonce and authenticated ciphertext. - Returns: A `Data` object containing the nonce and authenticated ciphertext.
*/ */
public func seal(message: Data, secretKey: Key) -> Data? { public func seal(message: Data, secretKey: Key) -> Data? {
guard let (authenticatedCipherText, nonce): (Data, Nonce) = seal(message: message, secretKey: secretKey) else { guard let (authenticatedCipherText, nonce): (Data, Nonce) = seal(message: message, secretKey: secretKey) else {
return nil return nil
} }
var nonceAndAuthenticatedCipherText = nonce var nonceAndAuthenticatedCipherText = nonce
nonceAndAuthenticatedCipherText.append(authenticatedCipherText) nonceAndAuthenticatedCipherText.append(authenticatedCipherText)
return nonceAndAuthenticatedCipherText return nonceAndAuthenticatedCipherText
} }
/** /**
Encrypts a message with a shared secret key. Encrypts a message with a shared secret key.
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter secretKey: The shared secret key. - Parameter secretKey: The shared secret key.
- Returns: The authenticated ciphertext and encryption nonce. - Returns: The authenticated ciphertext and encryption nonce.
*/ */
public func seal(message: Data, secretKey: Key) -> (authenticatedCipherText: Data, nonce: Nonce)? { public func seal(message: Data, secretKey: Key) -> (authenticatedCipherText: Data, nonce: Nonce)? {
if secretKey.count != KeyBytes { if secretKey.count != KeyBytes {
return nil return nil
} }
var authenticatedCipherText = Data(count: message.count + MacBytes) var authenticatedCipherText = Data(count: message.count + MacBytes)
let nonce = self.nonce() let nonce = self.nonce()
let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in let result = authenticatedCipherText.withUnsafeMutableBytes { authenticatedCipherTextPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_secretbox_easy( crypto_secretbox_easy(
authenticatedCipherTextPtr, authenticatedCipherTextPtr,
messagePtr, messagePtr, UInt64(message.count),
UInt64(message.count), noncePtr, secretKeyPtr)
noncePtr,
secretKeyPtr)
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return (authenticatedCipherText: authenticatedCipherText, nonce: nonce) return (authenticatedCipherText: authenticatedCipherText, nonce: nonce)
} }
/** /**
Encrypts a message with a shared secret key (detached mode). Encrypts a message with a shared secret key (detached mode).
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter secretKey: The shared secret key. - Parameter secretKey: The shared secret key.
- Returns: The encrypted ciphertext, encryption nonce, and authentication tag. - Returns: The encrypted ciphertext, encryption nonce, and authentication tag.
*/ */
public func seal(message: Data, secretKey: Key) -> (cipherText: Data, nonce: Nonce, mac: MAC)? { public func seal(message: Data, secretKey: Key) -> (cipherText: Data, nonce: Nonce, mac: MAC)? {
if secretKey.count != KeyBytes { if secretKey.count != KeyBytes {
return nil return nil
} }
var cipherText = Data(count: message.count) var cipherText = Data(count: message.count)
var mac = Data(count: MacBytes) var mac = Data(count: MacBytes)
let nonce = self.nonce() let nonce = self.nonce()
let result = cipherText.withUnsafeMutableBytes { cipherTextPtr in let result = cipherText.withUnsafeMutableBytes { cipherTextPtr in
return mac.withUnsafeMutableBytes { macPtr in mac.withUnsafeMutableBytes { macPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_secretbox_detached( crypto_secretbox_detached(
cipherTextPtr, cipherTextPtr, macPtr,
macPtr, messagePtr, UInt64(message.count),
messagePtr, noncePtr, secretKeyPtr)
UInt64(message.count),
noncePtr,
secretKeyPtr)
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return (cipherText: cipherText, nonce: nonce, mac: mac) return (cipherText: cipherText, nonce: nonce, mac: mac)
} }
/** /**
Decrypts a message with a shared secret key. Decrypts a message with a shared secret key.
- Parameter nonceAndAuthenticatedCipherText: A `Data` object containing the nonce and authenticated ciphertext. - Parameter nonceAndAuthenticatedCipherText: A `Data` object containing the nonce and authenticated ciphertext.
- Parameter secretKey: The shared secret key. - Parameter secretKey: The shared secret key.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(nonceAndAuthenticatedCipherText: Data, secretKey: Key) -> Data? { public func open(nonceAndAuthenticatedCipherText: Data, secretKey: Key) -> Data? {
if nonceAndAuthenticatedCipherText.count < MacBytes + NonceBytes { if nonceAndAuthenticatedCipherText.count < MacBytes + NonceBytes {
return nil return nil
} }
let nonce = nonceAndAuthenticatedCipherText.subdata(in: 0..<NonceBytes) as Nonce let nonce = nonceAndAuthenticatedCipherText.subdata(in: 0..<NonceBytes) as Nonce
let authenticatedCipherText = nonceAndAuthenticatedCipherText.subdata(in: NonceBytes..<nonceAndAuthenticatedCipherText.count) let authenticatedCipherText = nonceAndAuthenticatedCipherText.subdata(in: NonceBytes..<nonceAndAuthenticatedCipherText.count)
return open(authenticatedCipherText: authenticatedCipherText, secretKey: secretKey, nonce: nonce) return open(authenticatedCipherText: authenticatedCipherText, secretKey: secretKey, nonce: nonce)
} }
/** /**
Decrypts a message with a shared secret key and encryption nonce. Decrypts a message with a shared secret key and encryption nonce.
- Parameter authenticatedCipherText: The authenticated ciphertext. - Parameter authenticatedCipherText: The authenticated ciphertext.
- Parameter secretKey: The shared secret key. - Parameter secretKey: The shared secret key.
- Parameter nonce: The encryption nonce. - Parameter nonce: The encryption nonce.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(authenticatedCipherText: Data, secretKey: Key, nonce: Nonce) -> Data? { public func open(authenticatedCipherText: Data, secretKey: Key, nonce: Nonce) -> Data? {
if authenticatedCipherText.count < MacBytes { if authenticatedCipherText.count < MacBytes {
return nil return nil
} }
var message = Data(count: authenticatedCipherText.count - MacBytes) var message = Data(count: authenticatedCipherText.count - MacBytes)
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in authenticatedCipherText.withUnsafeBytes { authenticatedCipherTextPtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_secretbox_open_easy( crypto_secretbox_open_easy(
messagePtr, messagePtr,
authenticatedCipherTextPtr, authenticatedCipherTextPtr, UInt64(authenticatedCipherText.count),
UInt64(authenticatedCipherText.count), noncePtr, secretKeyPtr)
noncePtr,
secretKeyPtr)
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message return message
} }
/** /**
Decrypts a message with a shared secret key, encryption nonce, and authentication tag. Decrypts a message with a shared secret key, encryption nonce, and authentication tag.
- Parameter cipherText: The encrypted ciphertext. - Parameter cipherText: The encrypted ciphertext.
- Parameter secretKey: The shared secret key. - Parameter secretKey: The shared secret key.
- Parameter nonce: The encryption nonce. - Parameter nonce: The encryption nonce.
- Returns: The decrypted message. - Returns: The decrypted message.
*/ */
public func open(cipherText: Data, secretKey: Key, nonce: Nonce, mac: MAC) -> Data? { public func open(cipherText: Data, secretKey: Key, nonce: Nonce, mac: MAC) -> Data? {
if nonce.count != NonceBytes || mac.count != MacBytes { if nonce.count != NonceBytes || mac.count != MacBytes {
return nil return nil
} }
if secretKey.count != KeyBytes { if secretKey.count != KeyBytes {
return nil return nil
} }
var message = Data(count: cipherText.count) var message = Data(count: cipherText.count)
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return cipherText.withUnsafeBytes { cipherTextPtr in cipherText.withUnsafeBytes { cipherTextPtr in
return mac.withUnsafeBytes { macPtr in mac.withUnsafeBytes { macPtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_secretbox_open_detached( crypto_secretbox_open_detached(
messagePtr, messagePtr,
cipherTextPtr, cipherTextPtr, macPtr, UInt64(cipherText.count),
macPtr, noncePtr, secretKeyPtr)
UInt64(cipherText.count),
noncePtr,
secretKeyPtr)
} }
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message return message
} }
} }

View File

@ -2,16 +2,13 @@
// SecretStream.swift // SecretStream.swift
// Sodium_iOS // Sodium_iOS
// //
// Created by Frank Denis on 9/21/17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
public class SecretStream { public class SecretStream {
public let xchacha20poly1305 = XChaCha20Poly1305() public let xchacha20poly1305 = XChaCha20Poly1305()
public class XChaCha20Poly1305 { public class XChaCha20Poly1305 {
public static let ABytes = Int(crypto_secretstream_xchacha20poly1305_abytes()) public static let ABytes = Int(crypto_secretstream_xchacha20poly1305_abytes())
public static let HeaderBytes = Int(crypto_secretstream_xchacha20poly1305_headerbytes()) public static let HeaderBytes = Int(crypto_secretstream_xchacha20poly1305_headerbytes())
@ -24,10 +21,10 @@ public class SecretStream {
} }
public typealias Key = Data public typealias Key = Data
public typealias Header = Data public typealias Header = Data
/** /**
Generates a secret key. Generates a secret key.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> Key? { public func key() -> Key? {
@ -37,25 +34,41 @@ public class SecretStream {
} }
return secretKey return secretKey
} }
/**
Creates a new stream using the secret key `secretKey`
- Parameter secretKey: The secret key.
- Returns: A `PushStreamObject`. The stream header can be obtained by
calling the `header()` method of that returned object.
*/
public func initPush(secretKey: Key) -> PushStream? { public func initPush(secretKey: Key) -> PushStream? {
guard let stream = PushStream(secretKey: secretKey) else { guard let stream = PushStream(secretKey: secretKey) else {
return nil return nil
} }
return stream return stream
} }
/**
Starts reading a stream, whose header is `header`.
- Parameter secretKey: The secret key.
- Parameter header: The header.
- Returns: The stream to decrypt messages from.
*/
public func initPull(secretKey: Key, header: Header) -> PullStream? { public func initPull(secretKey: Key, header: Header) -> PullStream? {
guard let stream = PullStream(secretKey: secretKey, header: header) else { guard let stream = PullStream(secretKey: secretKey, header: header) else {
return nil return nil
} }
return stream return stream
} }
public class PushStream { public class PushStream {
private var state: UnsafeMutablePointer<crypto_secretstream_xchacha20poly1305_state>? private var state: UnsafeMutablePointer<crypto_secretstream_xchacha20poly1305_state>?
private var _header: Header private var _header: Header
init?(secretKey: Key) { init?(secretKey: Key) {
if secretKey.count != KeyBytes { if secretKey.count != KeyBytes {
return nil return nil
@ -75,20 +88,34 @@ public class SecretStream {
return nil return nil
} }
} }
/**
The header of the stream, required to decrypt it.
- Returns: The stream header.
*/
public func header() -> Header { public func header() -> Header {
return _header return _header
} }
public func push(message: Data, tag: Tag = Tag.MESSAGE, ad: Data? = nil) -> Data? { /**
Encrypts and authenticate a new message. Optionally also authenticate `ad`.
- Parameter message: The message to encrypt.
- Parameter tag: The tag to attach to the message. By default `.MESSAGE`.
You may want to use `.FINAL` for the last message of the stream instead.
- Parameter ad: Optional additional data to authenticate.
- Returns: The ciphertext.
*/
public func push(message: Data, tag: Tag = .MESSAGE, ad: Data? = nil) -> Data? {
var _ad = Data(count: 0) var _ad = Data(count: 0)
if ad != nil { if ad != nil {
_ad = ad! _ad = ad!
} }
let adx = Data(count:0)
var cipherText = Data(count: message.count + ABytes) var cipherText = Data(count: message.count + ABytes)
let result = cipherText.withUnsafeMutableBytes { cipherTextPtr in let result = cipherText.withUnsafeMutableBytes { cipherTextPtr in
adx.withUnsafeBytes { adPtr in _ad.withUnsafeBytes { adPtr in
message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
crypto_secretstream_xchacha20poly1305_push(self.state!, cipherTextPtr, nil, messagePtr, CUnsignedLongLong(message.count), adPtr, CUnsignedLongLong(_ad.count), tag.rawValue) crypto_secretstream_xchacha20poly1305_push(self.state!, cipherTextPtr, nil, messagePtr, CUnsignedLongLong(message.count), adPtr, CUnsignedLongLong(_ad.count), tag.rawValue)
} }
@ -99,11 +126,14 @@ public class SecretStream {
} }
return cipherText return cipherText
} }
/**
Performs an explicit key rotation.
*/
public func rekey() { public func rekey() {
crypto_secretstream_xchacha20poly1305_rekey(state) crypto_secretstream_xchacha20poly1305_rekey(state)
} }
deinit { deinit {
guard let state = state else { guard let state = state else {
return return
@ -112,10 +142,10 @@ public class SecretStream {
rawState.deallocate(capacity: 1) rawState.deallocate(capacity: 1)
} }
} }
public class PullStream { public class PullStream {
private var state: UnsafeMutablePointer<crypto_secretstream_xchacha20poly1305_state>? private var state: UnsafeMutablePointer<crypto_secretstream_xchacha20poly1305_state>?
init?(secretKey: Key, header: Header) { init?(secretKey: Key, header: Header) {
if header.count != HeaderBytes || secretKey.count != KeyBytes { if header.count != HeaderBytes || secretKey.count != KeyBytes {
return nil return nil
@ -134,7 +164,15 @@ public class SecretStream {
return nil return nil
} }
} }
/**
Decrypts a new message off the stream.
- Parameter cipherText: The encrypted message.
- Parameter ad: Optional additional data to authenticate.
- Returns: The decrypted message, as well as the tag attached to it.
*/
public func pull(cipherText: Data, ad: Data? = nil) -> (Data, Tag)? { public func pull(cipherText: Data, ad: Data? = nil) -> (Data, Tag)? {
if cipherText.count < ABytes { if cipherText.count < ABytes {
return nil return nil
@ -162,11 +200,14 @@ public class SecretStream {
} }
return (message, tag) return (message, tag)
} }
/**
Performs an explicit key rotation.
*/
public func rekey() { public func rekey() {
crypto_secretstream_xchacha20poly1305_rekey(state) crypto_secretstream_xchacha20poly1305_rekey(state)
} }
deinit { deinit {
guard let state = state else { guard let state = state else {
return return

View File

@ -2,9 +2,6 @@
// ShortHash.swift // ShortHash.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/28/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -12,12 +9,12 @@ import libsodium
public class ShortHash { public class ShortHash {
public let Bytes = Int(crypto_shorthash_bytes()) public let Bytes = Int(crypto_shorthash_bytes())
public let KeyBytes = Int(crypto_shorthash_keybytes()) public let KeyBytes = Int(crypto_shorthash_keybytes())
public typealias Key = Data public typealias Key = Data
/** /**
Generates a secret key. Generates a secret key.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> Key? { public func key() -> Key? {
@ -27,34 +24,31 @@ public class ShortHash {
} }
return k return k
} }
/** /**
Computes short but unpredictable (without knowing the secret key) values suitable for picking a list in a hash table for a given key. Computes short but unpredictable (without knowing the secret key) values suitable for picking a list in a hash table for a given key.
- Parameter message: The data to be hashed. - Parameter message: The data to be hashed.
- Parameter key: The hash key. Must be of length `KeyBytes`. Can be created using `RandomBytes.buf()`. - Parameter key: The hash key. Must be of length `KeyBytes`. Can be created using `RandomBytes.buf()`.
- Returns: The computed fingerprint. Will be of length `Bytes`. - Returns: The computed fingerprint.
*/ */
public func hash(message: Data, key: Data) -> Data? { public func hash(message: Data, key: Data) -> Data? {
if key.count != KeyBytes { if key.count != KeyBytes {
return nil return nil
} }
var output = Data(count: Bytes) var output = Data(count: Bytes)
let result = output.withUnsafeMutableBytes { outputPtr in let result = output.withUnsafeMutableBytes { outputPtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return key.withUnsafeBytes { keyPtr in key.withUnsafeBytes { keyPtr in
return crypto_shorthash(outputPtr, messagePtr, CUnsignedLongLong(message.count), keyPtr) crypto_shorthash(outputPtr, messagePtr, CUnsignedLongLong(message.count), keyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return output return output
} }
} }

View File

@ -2,9 +2,6 @@
// Sign.swift // Sign.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/28/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -15,209 +12,197 @@ public class Sign {
public let SecretKeyBytes = Int(crypto_sign_secretkeybytes()) public let SecretKeyBytes = Int(crypto_sign_secretkeybytes())
public let Bytes = Int(crypto_sign_bytes()) public let Bytes = Int(crypto_sign_bytes())
public let Primitive = String(validatingUTF8: crypto_sign_primitive()) public let Primitive = String(validatingUTF8: crypto_sign_primitive())
public typealias PublicKey = Data public typealias PublicKey = Data
public typealias SecretKey = Data public typealias SecretKey = Data
public struct KeyPair { public struct KeyPair {
public let publicKey: PublicKey public let publicKey: PublicKey
public let secretKey: SecretKey public let secretKey: SecretKey
public init(publicKey: PublicKey, secretKey: SecretKey) { public init(publicKey: PublicKey, secretKey: SecretKey) {
self.publicKey = publicKey self.publicKey = publicKey
self.secretKey = secretKey self.secretKey = secretKey
} }
} }
/** /**
Generates a signing secret key and a corresponding public key. Generates a signing secret key and a corresponding public key.
- Returns: A key pair containing the secret key and public key. - Returns: A key pair containing the secret key and public key.
*/ */
public func keyPair() -> KeyPair? { public func keyPair() -> KeyPair? {
var pk = Data(count: PublicKeyBytes) var pk = Data(count: PublicKeyBytes)
var sk = Data(count: SecretKeyBytes) var sk = Data(count: SecretKeyBytes)
let result = pk.withUnsafeMutableBytes { pkPtr in let result = pk.withUnsafeMutableBytes { pkPtr in
return sk.withUnsafeMutableBytes { skPtr in sk.withUnsafeMutableBytes { skPtr in
return crypto_sign_keypair(pkPtr, skPtr) crypto_sign_keypair(pkPtr, skPtr)
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return KeyPair(publicKey: pk, secretKey: sk)
return KeyPair(publicKey: pk,
secretKey: sk)
} }
/** /**
Generates a signing secret key and a corresponding public key derived from a seed. Generates a signing secret key and a corresponding public key derived from a seed.
- Parameter seed: The value from which to derive the secret and public key. - Parameter seed: The value from which to derive the secret and public key.
- Returns: A key pair containing the secret key and public key. - Returns: A key pair containing the secret key and public key.
*/ */
public func keyPair(seed: Data) -> KeyPair? { public func keyPair(seed: Data) -> KeyPair? {
if seed.count != SeedBytes { if seed.count != SeedBytes {
return nil return nil
} }
var pk = Data(count: PublicKeyBytes) var pk = Data(count: PublicKeyBytes)
var sk = Data(count: SecretKeyBytes) var sk = Data(count: SecretKeyBytes)
let result = pk.withUnsafeMutableBytes { pkPtr in let result = pk.withUnsafeMutableBytes { pkPtr in
return sk.withUnsafeMutableBytes { skPtr in sk.withUnsafeMutableBytes { skPtr in
return seed.withUnsafeBytes { seedPtr in seed.withUnsafeBytes { seedPtr in
return crypto_sign_seed_keypair(pkPtr, skPtr, seedPtr) crypto_sign_seed_keypair(pkPtr, skPtr, seedPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return KeyPair(publicKey: pk, secretKey: sk)
return KeyPair(publicKey: pk,
secretKey: sk)
} }
/** /**
Signs a message with the sender's secret key Signs a message with the sender's secret key
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter secretKey: The sender's secret key. - Parameter secretKey: The sender's secret key.
- Returns: The signed message. - Returns: The signed message.
*/ */
public func sign(message: Data, secretKey: SecretKey) -> Data? { public func sign(message: Data, secretKey: SecretKey) -> Data? {
if secretKey.count != SecretKeyBytes { if secretKey.count != SecretKeyBytes {
return nil return nil
} }
var signedMessage = Data(count: message.count + Bytes) var signedMessage = Data(count: message.count + Bytes)
let result = signedMessage.withUnsafeMutableBytes { signedMessagePtr in let result = signedMessage.withUnsafeMutableBytes { signedMessagePtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_sign( crypto_sign(
signedMessagePtr, signedMessagePtr, nil,
nil, messagePtr, CUnsignedLongLong(message.count),
messagePtr,
CUnsignedLongLong(message.count),
secretKeyPtr) secretKeyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return signedMessage return signedMessage
} }
/** /**
Computes a detached signature for a message with the sender's secret key. Computes a detached signature for a message with the sender's secret key.
- Parameter message: The message to encrypt. - Parameter message: The message to encrypt.
- Parameter secretKey: The sender's secret key. - Parameter secretKey: The sender's secret key.
- Returns: The computed signature. - Returns: The computed signature.
*/ */
public func signature(message: Data, secretKey: SecretKey) -> Data? { public func signature(message: Data, secretKey: SecretKey) -> Data? {
if secretKey.count != SecretKeyBytes { if secretKey.count != SecretKeyBytes {
return nil return nil
} }
var signature = Data(count: Bytes) var signature = Data(count: Bytes)
let result = signature.withUnsafeMutableBytes { signaturePtr in let result = signature.withUnsafeMutableBytes { signaturePtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_sign_detached( crypto_sign_detached(
signaturePtr, signaturePtr, nil,
nil, messagePtr, CUnsignedLongLong(message.count),
messagePtr,
CUnsignedLongLong(message.count),
secretKeyPtr) secretKeyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return signature return signature
} }
/** /**
Verifies a signed message with the sender's public key. Verifies a signed message with the sender's public key.
- Parameter signedMessage: The signed message to verify. - Parameter signedMessage: The signed message to verify.
- Parameter publicKey: The sender's public key. - Parameter publicKey: The sender's public key.
- Returns: `true` if verification is successful. - Returns: `true` if verification is successful.
*/ */
public func verify(signedMessage: Data, publicKey: PublicKey) -> Bool { public func verify(signedMessage: Data, publicKey: PublicKey) -> Bool {
let signature = signedMessage.subdata(in: 0..<Bytes) as Data let signature = signedMessage.subdata(in: 0..<Bytes) as Data
let message = signedMessage.subdata(in: Bytes..<signedMessage.count) as Data let message = signedMessage.subdata(in: Bytes..<signedMessage.count) as Data
return verify(message: message, publicKey: publicKey, signature: signature) return verify(message: message, publicKey: publicKey, signature: signature)
} }
/** /**
Verifies the detached signature of a message with the sender's public key. Verifies the detached signature of a message with the sender's public key.
- Parameter message: The message to verify. - Parameter message: The message to verify.
- Parameter publicKey: The sender's public key. - Parameter publicKey: The sender's public key.
- Parameter signature: The detached signature to verify. - Parameter signature: The detached signature to verify.
- Returns: `true` if verification is successful. - Returns: `true` if verification is successful.
*/ */
public func verify(message: Data, publicKey: PublicKey, signature: Data) -> Bool { public func verify(message: Data, publicKey: PublicKey, signature: Data) -> Bool {
if publicKey.count != PublicKeyBytes { if publicKey.count != PublicKeyBytes {
return false return false
} }
return signature.withUnsafeBytes { signaturePtr in return signature.withUnsafeBytes { signaturePtr in
return message.withUnsafeBytes { messagePtr in message.withUnsafeBytes { messagePtr in
return publicKey.withUnsafeBytes { publicKeyPtr in publicKey.withUnsafeBytes { publicKeyPtr in
return crypto_sign_verify_detached( crypto_sign_verify_detached(
signaturePtr, signaturePtr,
messagePtr, messagePtr, CUnsignedLongLong(message.count), publicKeyPtr) == 0
CUnsignedLongLong(message.count), publicKeyPtr) == 0
} }
} }
} }
} }
/** /**
Extracts and returns the message data of a signed message if the signature is verified with the sender's secret key. Extracts and returns the message data of a signed message if the signature is verified with the sender's secret key.
- Parameter signedMessage: The signed message to open. - Parameter signedMessage: The signed message to open.
- Parameter publicKey: The sender's public key. - Parameter publicKey: The sender's public key.
- Returns: The message data if verification is successful. - Returns: The message data if verification is successful.
*/ */
public func open(signedMessage: Data, publicKey: PublicKey) -> Data? { public func open(signedMessage: Data, publicKey: PublicKey) -> Data? {
if publicKey.count != PublicKeyBytes || signedMessage.count < Bytes { if publicKey.count != PublicKeyBytes || signedMessage.count < Bytes {
return nil return nil
} }
var message = Data(count: signedMessage.count - Bytes) var message = Data(count: signedMessage.count - Bytes)
var mlen: CUnsignedLongLong = 0 var mlen: CUnsignedLongLong = 0
let result = message.withUnsafeMutableBytes { messagePtr in let result = message.withUnsafeMutableBytes { messagePtr in
return signedMessage.withUnsafeBytes { signedMessagePtr in signedMessage.withUnsafeBytes { signedMessagePtr in
return publicKey.withUnsafeBytes { publicKeyPtr in publicKey.withUnsafeBytes { publicKeyPtr in
return crypto_sign_open(messagePtr, &mlen, signedMessagePtr, CUnsignedLongLong(signedMessage.count), publicKeyPtr) crypto_sign_open(
messagePtr, &mlen,
signedMessagePtr, CUnsignedLongLong(signedMessage.count),
publicKeyPtr)
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return message return message
} }
} }

View File

@ -2,9 +2,6 @@
// Sodium.swift // Sodium.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/27/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -23,13 +20,13 @@ public class Sodium {
public let stream = Stream() public let stream = Stream()
public let keyDerivation = KeyDerivation() public let keyDerivation = KeyDerivation()
public let secretStream = SecretStream() public let secretStream = SecretStream()
private static let once: Void = { private static let once: Void = {
if sodium_init() == -1 { if sodium_init() < 0 {
fatalError("Failed to initialize libSodium") fatalError("Failed to initialize libsodium")
} }
}() }()
public init() { public init() {
_ = Sodium.once _ = Sodium.once
} }

View File

@ -2,9 +2,6 @@
// Stream.swift // Stream.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 5/30/17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
@ -13,13 +10,13 @@ public class Stream {
public let KeyBytes = Int(crypto_secretbox_keybytes()) public let KeyBytes = Int(crypto_secretbox_keybytes())
public let NonceBytes = Int(crypto_secretbox_noncebytes()) public let NonceBytes = Int(crypto_secretbox_noncebytes())
public let Primitive = String.init(validatingUTF8: crypto_stream_primitive()) public let Primitive = String.init(validatingUTF8: crypto_stream_primitive())
public typealias Key = Data public typealias Key = Data
public typealias Nonce = Data public typealias Nonce = Data
/** /**
Generates a secret key. Generates a secret key.
- Returns: The generated key. - Returns: The generated key.
*/ */
public func key() -> Key? { public func key() -> Key? {
@ -29,10 +26,10 @@ public class Stream {
} }
return k return k
} }
/** /**
Generates a random nonce. Generates a random nonce.
- Returns: The generated nonce. - Returns: The generated nonce.
*/ */
public func nonce() -> Nonce { public func nonce() -> Nonce {
@ -42,14 +39,18 @@ public class Stream {
} }
return nonce return nonce
} }
/** /**
XOR the input with a key stream derived from a secret key and a nonce. XOR the input with a key stream derived from a secret key and a nonce.
Applying the same operation twice outputs the original input. Applying the same operation twice outputs the original input.
No authentication tag is added to the output. The data can be tampered with; an adversary can flip arbitrary bits. No authentication tag is added to the output. The data can be tampered with; an adversary can flip arbitrary bits.
In order to encrypt data using a secret key, the SecretBox class is likely to be what you are looking for. In order to encrypt data using a secret key, the SecretBox class is likely to be what you are looking for.
In order to generate a deterministic stream out of a seed, the RandomBytes.deterministic_rand() function is likely to be what you need. In order to generate a deterministic stream out of a seed, the RandomBytes.deterministic_rand() function is likely to be what you need.
- Parameter input: Input data
- Parameter nonce: Nonce
- Parameter secretKey: The secret key
- Returns: input XOR keystream(secretKey, nonce) - Returns: input XOR keystream(secretKey, nonce)
*/ */
public func xor(input: Data, nonce: Nonce, secretKey: Key) -> Data? { public func xor(input: Data, nonce: Nonce, secretKey: Key) -> Data? {
@ -59,28 +60,30 @@ public class Stream {
var output = Data(count: input.count) var output = Data(count: input.count)
let result = output.withUnsafeMutableBytes { outputPtr in let result = output.withUnsafeMutableBytes { outputPtr in
input.withUnsafeBytes { inputPtr in input.withUnsafeBytes { inputPtr in
return nonce.withUnsafeBytes { noncePtr in nonce.withUnsafeBytes { noncePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_stream_xor(outputPtr, inputPtr, UInt64(input.count), noncePtr, secretKeyPtr) crypto_stream_xor(outputPtr, inputPtr, UInt64(input.count), noncePtr, secretKeyPtr)
} }
} }
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
return output return output
} }
/** /**
XOR the input with a key stream derived from a secret key and a random nonce. XOR the input with a key stream derived from a secret key and a random nonce.
Applying the same operation twice outputs the original input. Applying the same operation twice outputs the original input.
No authentication tag is added to the output. The data can be tampered with; an adversary can flip arbitrary bits. No authentication tag is added to the output. The data can be tampered with; an adversary can flip arbitrary bits.
In order to encrypt data using a secret key, the SecretBox class is likely to be what you are looking for. In order to encrypt data using a secret key, the SecretBox class is likely to be what you are looking for.
In order to generate a deterministic stream out of a seed, the RandomBytes.deterministic_rand() function is likely to be what you need. In order to generate a deterministic stream out of a seed, the RandomBytes.deterministic_rand() function is likely to be what you need.
- Parameter input: Input data
- Parameter nonce: Nonce
- Parameter secretKey: The secret key
- Returns: (input XOR keystream(secretKey, nonce), nonce) - Returns: (input XOR keystream(secretKey, nonce), nonce)
*/ */
public func xor(input: Data, secretKey: Key) -> (output:Data, nonce: Nonce)? { public func xor(input: Data, secretKey: Key) -> (output:Data, nonce: Nonce)? {

View File

@ -2,18 +2,14 @@
// Utils.swift // Utils.swift
// Sodium // Sodium
// //
// Created by Frank Denis on 12/27/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation import Foundation
import libsodium import libsodium
public class Utils { public class Utils {
/** /**
Tries to effectively zero bytes in `data`, even if optimizations are being applied to the code. Tries to effectively zero bytes in `data`, even if optimizations are being applied to the code.
- Parameter data: The `Data` object to zero. - Parameter data: The `Data` object to zero.
*/ */
public func zero(_ data: inout Data) { public func zero(_ data: inout Data) {
@ -21,174 +17,166 @@ public class Utils {
data.withUnsafeMutableBytes { (dataPtr: UnsafeMutablePointer<UInt8>) in data.withUnsafeMutableBytes { (dataPtr: UnsafeMutablePointer<UInt8>) in
let rawPtr = UnsafeMutableRawPointer(dataPtr) let rawPtr = UnsafeMutableRawPointer(dataPtr)
sodium_memzero(rawPtr, count) sodium_memzero(rawPtr, count)
return
} }
} }
/** /**
Checks that two `Data` objects have the same content, without leaking information
about the actual content of these objects.
- Parameter b1: first object
- Parameter b2: second object
- Returns: `true` if the bytes in `b1` match the bytes in `b2`. Otherwise, it returns false. - Returns: `true` if the bytes in `b1` match the bytes in `b2`. Otherwise, it returns false.
*/ */
public func equals(_ b1: Data, _ b2: Data) -> Bool { public func equals(_ b1: Data, _ b2: Data) -> Bool {
if b1.count != b2.count { if b1.count != b2.count {
return false return false
} }
return b1.withUnsafeBytes { b1Ptr in return b1.withUnsafeBytes { b1Ptr in
return b2.withUnsafeBytes { b2Ptr in b2.withUnsafeBytes { b2Ptr in
return Int(sodium_memcmp( Int(sodium_memcmp(
UnsafeRawPointer(b1Ptr), UnsafeRawPointer(b1Ptr), UnsafeRawPointer(b2Ptr), b1.count)) == 0
UnsafeRawPointer(b2Ptr),
b1.count)) == 0
} }
} }
} }
/** /**
- Returns: 0 if the bytes in `b1` match the bytes in `b2`. Otherwise, it returns -1. Compares two `Data` objects without leaking information about the content of these objects.
- Returns: `0` if the bytes in `b1` match the bytes in `b2`.
`-1` if `b2` is less than `b1` (considered as little-endian values) and
`1` if `b1` is less than `b2` (considered as little-endian values)
*/ */
public func compare(_ b1: Data, _ b2: Data) -> Int? { public func compare(_ b1: Data, _ b2: Data) -> Int? {
if b1.count != b2.count { if b1.count != b2.count {
return nil return nil
} }
return b1.withUnsafeBytes { b1Ptr in return b1.withUnsafeBytes { b1Ptr in
return b2.withUnsafeBytes { b2Ptr in b2.withUnsafeBytes { b2Ptr in
return Int(sodium_compare( Int(sodium_compare(
b1Ptr, b1Ptr, b2Ptr, b1.count))
b2Ptr,
b1.count))
} }
} }
} }
/** /**
Converts bytes stored in `bin` into a hexadecimal string. Converts bytes stored in `bin` into a hexadecimal string.
- Parameter bin: The data to encode as hexdecimal. - Parameter bin: The data to encode as hexdecimal.
- Returns: The encoded hexdecimal string. - Returns: The encoded hexdecimal string.
*/ */
public func bin2hex(_ bin: Data) -> String? { public func bin2hex(_ bin: Data) -> String? {
var hexData = Data(count: bin.count * 2 + 1) var hexData = Data(count: bin.count * 2 + 1)
return hexData.withUnsafeMutableBytes { (hexPtr: UnsafeMutablePointer<Int8>) -> String? in return hexData.withUnsafeMutableBytes { (hexPtr: UnsafeMutablePointer<Int8>) -> String? in
return bin.withUnsafeBytes { (binPtr: UnsafePointer<UInt8>) -> String? in bin.withUnsafeBytes { (binPtr: UnsafePointer<UInt8>) -> String? in
if sodium_bin2hex(hexPtr, hexData.count, binPtr, bin.count) == nil { if sodium_bin2hex(hexPtr, hexData.count, binPtr, bin.count) == nil {
return nil return nil
} }
return String.init(validatingUTF8: hexPtr) return String.init(validatingUTF8: hexPtr)
} }
} }
} }
/** /**
Decode as a hexdecimal string, ignoring characters included for readability. Decodes a hexdecimal string, ignoring characters included for readability.
- Parameter hex: The hexdecimal string to decode. - Parameter hex: The hexdecimal string to decode.
- Parameter ignore: Optional string containing readability characters to ignore during decoding. - Parameter ignore: Optional string containing readability characters to ignore during decoding.
- Returns: The decoded data. - Returns: The decoded data.
*/ */
public func hex2bin(_ hex: String, ignore: String? = nil) -> Data? { public func hex2bin(_ hex: String, ignore: String? = nil) -> Data? {
guard let hexData = hex.data(using: .utf8, allowLossyConversion: false) else { guard let hexData = hex.data(using: .utf8, allowLossyConversion: false) else {
return nil return nil
} }
let hexDataLen = hexData.count let hexDataLen = hexData.count
let binDataCapacity = hexDataLen / 2 let binDataCapacity = hexDataLen / 2
var binData = Data(count: binDataCapacity) var binData = Data(count: binDataCapacity)
var binDataLen: size_t = 0 var binDataLen: size_t = 0
let ignore_cstr = ignore != nil ? (ignore! as NSString).utf8String : nil let ignore_cstr = ignore != nil ? (ignore! as NSString).utf8String : nil
let result = binData.withUnsafeMutableBytes { binPtr in let result = binData.withUnsafeMutableBytes { binPtr in
return hexData.withUnsafeBytes { hexPtr in hexData.withUnsafeBytes { hexPtr in
return sodium_hex2bin(binPtr, sodium_hex2bin(binPtr, binDataCapacity,
binDataCapacity, hexPtr, hexDataLen,
hexPtr, ignore_cstr, &binDataLen, nil)
hexDataLen,
ignore_cstr,
&binDataLen,
nil)
} }
} }
if result != 0 {
if result != 0 {
return nil return nil
} }
binData.count = Int(binDataLen) binData.count = Int(binDataLen)
return binData return binData
} }
public enum Base64Variant: CInt { public enum Base64Variant: CInt {
case ORIGINAL = 1 case ORIGINAL = 1
case ORIGINAL_NO_PADDING = 3 case ORIGINAL_NO_PADDING = 3
case URLSAFE = 5 case URLSAFE = 5
case URLSAFE_NO_PADDING = 7 case URLSAFE_NO_PADDING = 7
} }
/** /**
Converts bytes stored in `bin` into a Base64 representation. Converts bytes stored in `bin` into a Base64 representation.
- Parameter bin: The data to encode as Base64. - Parameter bin: The data to encode as Base64.
- Parameter variant: the Base64 variant to use. By default: URLSAFE. - Parameter variant: the Base64 variant to use. By default: URLSAFE.
- Returns: The encoded base64 string. - Returns: The encoded base64 string.
*/ */
public func bin2base64(_ bin: Data, variant: Base64Variant = Base64Variant.URLSAFE) -> String? { public func bin2base64(_ bin: Data, variant: Base64Variant = .URLSAFE) -> String? {
var b64Data = Data(count: sodium_base64_encoded_len(bin.count, variant.rawValue)) var b64Data = Data(count: sodium_base64_encoded_len(bin.count, variant.rawValue))
return b64Data.withUnsafeMutableBytes { (b64Ptr: UnsafeMutablePointer<Int8>) -> String? in return b64Data.withUnsafeMutableBytes { (b64Ptr: UnsafeMutablePointer<Int8>) -> String? in
return bin.withUnsafeBytes { (binPtr: UnsafePointer<UInt8>) -> String? in bin.withUnsafeBytes { (binPtr: UnsafePointer<UInt8>) -> String? in
if sodium_bin2base64(b64Ptr, b64Data.count, binPtr, bin.count, variant.rawValue) == nil { if sodium_bin2base64(b64Ptr, b64Data.count, binPtr, bin.count, variant.rawValue) == nil {
return nil return nil
} }
return String.init(validatingUTF8: b64Ptr) return String.init(validatingUTF8: b64Ptr)
} }
} }
} }
/* /*
Decode as a base64 string, ignoring characters included for readability. Decodes a Base64 string, ignoring characters included for readability.
- Parameter b64: The base64 string to decode. - Parameter b64: The Base64 string to decode.
- Parameter ignore: Optional string containing readability characters to ignore during decoding. - Parameter ignore: Optional string containing readability characters to ignore during decoding.
- Returns: The decoded data. - Returns: The decoded data.
*/ */
public func base642bin(_ b64: String, variant: Base64Variant = Base64Variant.URLSAFE, ignore: String? = nil) -> Data? { public func base642bin(_ b64: String, variant: Base64Variant = .URLSAFE, ignore: String? = nil) -> Data? {
guard let b64Data = b64.data(using: .utf8, allowLossyConversion: false) else { guard let b64Data = b64.data(using: .utf8, allowLossyConversion: false) else {
return nil return nil
} }
let b64DataLen = b64Data.count let b64DataLen = b64Data.count
let binDataCapacity = b64DataLen * 3 / 4 let binDataCapacity = b64DataLen * 3 / 4
var binData = Data(count: binDataCapacity) var binData = Data(count: binDataCapacity)
var binDataLen: size_t = 0 var binDataLen: size_t = 0
let ignore_cstr = ignore != nil ? (ignore! as NSString).utf8String : nil let ignore_cstr = ignore != nil ? (ignore! as NSString).utf8String : nil
let result = binData.withUnsafeMutableBytes { binPtr in let result = binData.withUnsafeMutableBytes { binPtr in
b64Data.withUnsafeBytes { b64Ptr in b64Data.withUnsafeBytes { b64Ptr in
sodium_base642bin(binPtr, sodium_base642bin(binPtr, binDataCapacity,
binDataCapacity, b64Ptr, b64DataLen,
b64Ptr, ignore_cstr, &binDataLen, nil, variant.rawValue)
b64DataLen,
ignore_cstr,
&binDataLen,
nil, variant.rawValue)
} }
} }
if result != 0 { if result != 0 {
return nil return nil
} }
binData.count = Int(binDataLen) binData.count = Int(binDataLen)
return binData return binData
} }
/* /*
Add padding to `data` so that its length becomes a multiple of `blockSize` Adds padding to `data` so that its length becomes a multiple of `blockSize`
- Parameter data: input/output buffer, will be modified in-place - Parameter data: input/output buffer, will be modified in-place
- Parameter blocksize: the block size - Parameter blocksize: the block size
*/ */
@ -204,13 +192,13 @@ public class Utils {
return nil return nil
} }
data.count = Int(paddedLen) data.count = Int(paddedLen)
return () return ()
} }
/* /*
Remove padding from `data` to restore its original size Removes padding from `data` to restore its original size
- Parameter data: input/output buffer, will be modified in-place - Parameter data: input/output buffer, will be modified in-place
- Parameter blocksize: the block size - Parameter blocksize: the block size
*/ */
@ -223,7 +211,7 @@ public class Utils {
return nil return nil
} }
data.count = Int(unpaddedLen) data.count = Int(unpaddedLen)
return () return ()
} }
} }

View File

@ -223,8 +223,7 @@ class ReadmeTests : XCTestCase {
let header = stream_enc.header() let header = stream_enc.header()
let encrypted1 = stream_enc.push(message: message1)! let encrypted1 = stream_enc.push(message: message1)!
let encrypted2 = stream_enc.push(message: message2)! let encrypted2 = stream_enc.push(message: message2)!
let encrypted3 = stream_enc.push(message: message3, let encrypted3 = stream_enc.push(message: message3, tag: .FINAL)!
tag: SecretStream.XChaCha20Poly1305.Tag.FINAL)!
/* stream decryption */ /* stream decryption */
@ -236,19 +235,19 @@ class ReadmeTests : XCTestCase {
XCTAssertEqual(message1, message1_dec) XCTAssertEqual(message1, message1_dec)
XCTAssertEqual(message2, message2_dec) XCTAssertEqual(message2, message2_dec)
XCTAssertEqual(message3, message3_dec) XCTAssertEqual(message3, message3_dec)
XCTAssertEqual(tag1, SecretStream.XChaCha20Poly1305.Tag.MESSAGE) XCTAssertEqual(tag1, .MESSAGE)
XCTAssertEqual(tag2, SecretStream.XChaCha20Poly1305.Tag.MESSAGE) XCTAssertEqual(tag2, .MESSAGE)
XCTAssertEqual(tag3, SecretStream.XChaCha20Poly1305.Tag.FINAL) XCTAssertEqual(tag3, .FINAL)
} }
func testBase64() { func testBase64() {
let sodium = Sodium() let sodium = Sodium()
let b64 = sodium.utils.bin2base64("data".toData()!)! let b64 = sodium.utils.bin2base64("data".toData()!)!
let b64_2 = sodium.utils.bin2base64("data".toData()!, variant: Utils.Base64Variant.URLSAFE_NO_PADDING)! let b64_2 = sodium.utils.bin2base64("data".toData()!, variant: .URLSAFE_NO_PADDING)!
let data1 = sodium.utils.base642bin(b64) let data1 = sodium.utils.base642bin(b64)
let data2 = sodium.utils.base642bin(b64, ignore: " \n") let data2 = sodium.utils.base642bin(b64, ignore: " \n")
let data3 = sodium.utils.base642bin(b64_2, variant: Utils.Base64Variant.URLSAFE_NO_PADDING, ignore: " \n") let data3 = sodium.utils.base642bin(b64_2, variant: .URLSAFE_NO_PADDING, ignore: " \n")
XCTAssertEqual(data1, "data".toData()) XCTAssertEqual(data1, "data".toData())
XCTAssertEqual(data2, "data".toData()) XCTAssertEqual(data2, "data".toData())

View File

@ -241,8 +241,8 @@ class SodiumTests: XCTestCase {
let aliceKeyPair = sodium.keyExchange.keyPair()! let aliceKeyPair = sodium.keyExchange.keyPair()!
let bobKeyPair = sodium.keyExchange.keyPair()! let bobKeyPair = sodium.keyExchange.keyPair()!
let sessionKeyPairForAlice = sodium.keyExchange.sessionKeyPair(publicKey: aliceKeyPair.publicKey, secretKey: aliceKeyPair.secretKey, otherPublicKey: bobKeyPair.publicKey, side: .client)! let sessionKeyPairForAlice = sodium.keyExchange.sessionKeyPair(publicKey: aliceKeyPair.publicKey, secretKey: aliceKeyPair.secretKey, otherPublicKey: bobKeyPair.publicKey, side: .CLIENT)!
let sessionKeyPairForBob = sodium.keyExchange.sessionKeyPair(publicKey: bobKeyPair.publicKey, secretKey: bobKeyPair.secretKey, otherPublicKey: aliceKeyPair.publicKey, side: .server)! let sessionKeyPairForBob = sodium.keyExchange.sessionKeyPair(publicKey: bobKeyPair.publicKey, secretKey: bobKeyPair.secretKey, otherPublicKey: aliceKeyPair.publicKey, side: .SERVER)!
XCTAssertEqual(sessionKeyPairForAlice.rx, sessionKeyPairForBob.tx) XCTAssertEqual(sessionKeyPairForAlice.rx, sessionKeyPairForBob.tx)
XCTAssertEqual(sessionKeyPairForAlice.tx, sessionKeyPairForBob.rx) XCTAssertEqual(sessionKeyPairForAlice.tx, sessionKeyPairForBob.rx)
@ -328,15 +328,15 @@ class SodiumTests: XCTestCase {
let header = stream.header() let header = stream.header()
let encrypted1 = stream.push(message: "message 1".toData()!)! let encrypted1 = stream.push(message: "message 1".toData()!)!
let encrypted2 = stream.push(message: "message 2".toData()!)! let encrypted2 = stream.push(message: "message 2".toData()!)!
let encrypted3 = stream.push(message: "message 3".toData()!, tag: SecretStream.XChaCha20Poly1305.Tag.FINAL)! let encrypted3 = stream.push(message: "message 3".toData()!, tag: .FINAL)!
let stream2 = sodium.secretStream.xchacha20poly1305.initPull(secretKey: secretKey, header: header)! let stream2 = sodium.secretStream.xchacha20poly1305.initPull(secretKey: secretKey, header: header)!
let (message1, tag1) = stream2.pull(cipherText: encrypted1)! let (message1, tag1) = stream2.pull(cipherText: encrypted1)!
let (message2, tag2) = stream2.pull(cipherText: encrypted2)! let (message2, tag2) = stream2.pull(cipherText: encrypted2)!
let (message3, tag3) = stream2.pull(cipherText: encrypted3)! let (message3, tag3) = stream2.pull(cipherText: encrypted3)!
XCTAssertEqual(tag1, SecretStream.XChaCha20Poly1305.Tag.MESSAGE) XCTAssertEqual(tag1, .MESSAGE)
XCTAssertEqual(tag2, SecretStream.XChaCha20Poly1305.Tag.MESSAGE) XCTAssertEqual(tag2, .MESSAGE)
XCTAssertEqual(tag3, SecretStream.XChaCha20Poly1305.Tag.FINAL) XCTAssertEqual(tag3, .FINAL)
XCTAssertEqual(message1, "message 1".toData()!) XCTAssertEqual(message1, "message 1".toData()!)
XCTAssertEqual(message2, "message 2".toData()!) XCTAssertEqual(message2, "message 2".toData()!)
XCTAssertEqual(message3, "message 3".toData()!) XCTAssertEqual(message3, "message 3".toData()!)
@ -350,8 +350,8 @@ class SodiumTests: XCTestCase {
XCTAssertEqual(b64, "dGVzdA==") XCTAssertEqual(b64, "dGVzdA==")
XCTAssertEqual(bin2, bin) XCTAssertEqual(bin2, bin)
let b64_nopad = sodium.utils.bin2base64(bin, variant: Utils.Base64Variant.URLSAFE_NO_PADDING)! let b64_nopad = sodium.utils.bin2base64(bin, variant: .URLSAFE_NO_PADDING)!
let bin2_nopad = sodium.utils.base642bin(b64_nopad, variant: Utils.Base64Variant.URLSAFE_NO_PADDING)! let bin2_nopad = sodium.utils.base642bin(b64_nopad, variant: .URLSAFE_NO_PADDING)!
XCTAssertEqual(b64_nopad, "dGVzdA") XCTAssertEqual(b64_nopad, "dGVzdA")
XCTAssertEqual(bin2_nopad, bin) XCTAssertEqual(bin2_nopad, bin)
} }