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 encrypted1 = stream_enc.push(message: message1)!
let encrypted2 = stream_enc.push(message: message2)!
let encrypted3 = stream_enc.push(message: message3,
tag: SecretStream.XChaCha20Poly1305.Tag.FINAL)!
let encrypted3 = stream_enc.push(message: message3, tag: .FINAL)!
/* stream decryption */
@ -257,9 +256,9 @@ let aliceKeyPair = sodium.keyExchange.keyPair()!
let bobKeyPair = sodium.keyExchange.keyPair()!
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,
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 bobToAliceKeyEquality = sodium.utils.equals(sessionKeyPairForAlice.rx, sessionKeyPairForBob.tx) // true
@ -365,7 +364,7 @@ Constant-time base64 encoding
```swift
let sodium = Sodium()
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
@ -374,7 +373,7 @@ Base64 decoding
```swift
let data1 = sodium.utils.base642bin(b64)
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

View File

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

View File

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

View File

@ -2,9 +2,6 @@
// GenericHash.swift
// Sodium
//
// Created by Frank Denis on 12/27/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
@ -17,12 +14,12 @@ public class GenericHash {
public let KeyBytesMax = Int(crypto_generichash_keybytes_max())
public let KeyBytes = Int(crypto_generichash_keybytes())
public let Primitive = String.init(validatingUTF8: crypto_generichash_primitive())
public typealias Key = Data
/**
Generates a secret key.
- Returns: The generated key.
*/
public func key() -> Key? {
@ -32,126 +29,116 @@ public class GenericHash {
}
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.
- Parameter message: The message from which to compute the fingerprint.
- Parameter key: Optional key to use while computing the fingerprint.
- Returns: The computed fingerprint.
*/
public func hash(message: Data, key: Data? = nil) -> Data? {
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.
- Parameter message: The message from which to compute the fingerprint.
- Parameter key: The key to use while computing the fingerprint.
- Parameter outputLength: Desired length of the computed fingerprint.
- Returns: The computed fingerprint.
*/
public func hash(message: Data, key: Data?, outputLength: Int) -> Data? {
var output = Data(count: outputLength)
var result: Int32 = -1
if let key = key {
result = output.withUnsafeMutableBytes { outputPtr in
return message.withUnsafeBytes { messagePtr in
return key.withUnsafeBytes { keyPtr in
return crypto_generichash(
outputPtr,
output.count,
messagePtr,
CUnsignedLongLong(message.count),
keyPtr,
key.count)
message.withUnsafeBytes { messagePtr in
key.withUnsafeBytes { keyPtr in
crypto_generichash(
outputPtr, output.count,
messagePtr, CUnsignedLongLong(message.count),
keyPtr, key.count)
}
}
}
} else {
result = output.withUnsafeMutableBytes { outputPtr in
return message.withUnsafeBytes { messagePtr in
return crypto_generichash(
outputPtr,
output.count,
messagePtr,
CUnsignedLongLong(message.count),
nil,
0)
message.withUnsafeBytes { messagePtr in
crypto_generichash(
outputPtr, output.count,
messagePtr, CUnsignedLongLong(message.count),
nil, 0)
}
}
}
if result != 0 {
return nil
}
return output
}
/**
Computes a fixed-length fingerprint for an arbitrary long message.
- Parameter message: The message from which to compute the fingerprint.
- Parameter outputLength: Desired length of the computed fingerprint.
- Returns: The computed fingerprint.
*/
public func hash(message: Data, outputLength: Int) -> Data? {
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.
- Parameter key: Optional key to use while computing the fingerprint.
- Returns: The initialized `Stream`.
*/
public func initStream(key: Data? = nil) -> Stream? {
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.
- Parameter key: Optional key to use while computing the fingerprint.
- Parameter outputLength: Desired length of the computed fingerprint.
- Returns: The initialized `Stream`.
*/
public func initStream(key: Data?, outputLength: Int) -> Stream? {
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.
- Parameter: outputLength: Desired length of the computed fingerprint.
- Returns: The initialized `Stream`.
*/
public func initStream(outputLength: Int) -> Stream? {
return Stream(key: nil, outputLength: outputLength)
}
public class Stream {
public var outputLength: Int = 0
private var state: UnsafeMutablePointer<crypto_generichash_state>?
init?(key: Data?, outputLength: Int) {
let rawState = UnsafeMutablePointer<UInt8>.allocate(capacity: crypto_generichash_statebytes())
state = UnsafeMutableRawPointer(rawState).bindMemory(to: crypto_generichash_state.self, capacity: 1)
guard let state = state else {
return nil
}
var result: Int32 = -1
if let key = key {
result = key.withUnsafeBytes { keyPtr in
crypto_generichash_init(state, keyPtr, key.count, outputLength)
@ -159,14 +146,12 @@ public class GenericHash {
} else {
result = crypto_generichash_init(state, nil, 0, outputLength)
}
if result != 0 {
return nil
}
self.outputLength = outputLength
}
deinit {
guard let state = state else {
return
@ -174,23 +159,23 @@ public class GenericHash {
let rawState = UnsafeMutableRawPointer(state).bindMemory(to: UInt8.self, capacity: crypto_generichash_statebytes())
rawState.deallocate(capacity: 1)
}
/**
Updates the hash stream with incoming data to contribute to the computed fingerprint.
- Parameter input: The incoming stream data.
- Returns: `true` if the data was consumed successfully.
*/
public func update(input: Data) -> Bool {
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.
- Returns: The computed fingerprint.
*/
public func final() -> Data? {
@ -198,11 +183,9 @@ public class GenericHash {
let result = output.withUnsafeMutableBytes { outputPtr in
crypto_generichash_final(state!, outputPtr, output.count)
}
if result != 0 {
return nil
}
return output
}
}

View File

@ -2,9 +2,6 @@
// KeyDerivation.swift
// Sodium
//
// Created by Patrick Salami (https://www.github.com/psalami) on 7/7/17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
@ -14,13 +11,13 @@ public class KeyDerivation {
public let BytesMax = Int(crypto_kdf_bytes_max())
public let KeyBytes = Int(crypto_kdf_keybytes())
public let ContextBytes = Int(crypto_kdf_contextbytes())
public typealias Key = Data
public typealias SubKey = Data
/**
Generates a secret key.
- Returns: The generated key.
*/
public func key() -> Key? {
@ -30,17 +27,18 @@ public class KeyDerivation {
}
return k
}
/**
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.
- 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 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)
- 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.
*/
public func derive(secretKey: Data, index: UInt64, length: Int, context: String) -> Data? {
@ -54,17 +52,16 @@ public class KeyDerivation {
if contextBin.count > ContextBytes {
return nil
}
while contextBin.count < ContextBytes {
contextBin += [0]
}
var output = Data(count: length)
let result = output.withUnsafeMutableBytes { outputPtr in
return secretKey.withUnsafeBytes { secretKeyPtr in
return contextBin.withUnsafeBytes { contextBinPtr in
return crypto_kdf_derive_from_key(outputPtr, length, index, contextBinPtr, secretKeyPtr)
secretKey.withUnsafeBytes { secretKeyPtr in
contextBin.withUnsafeBytes { contextBinPtr in
crypto_kdf_derive_from_key(outputPtr, length, index, contextBinPtr, secretKeyPtr)
}
}
}

View File

@ -2,145 +2,130 @@
// KeyExchange.swift
// Sodium
//
// Created by Andreas Ganske on 17.03.17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
public class KeyExchange {
public let PublicKeyBytes = Int(crypto_kx_publickeybytes())
public let SecretKeyBytes = Int(crypto_kx_secretkeybytes())
public let SessionKeyBytes = Int(crypto_kx_sessionkeybytes())
public let SeedBytes = Int(crypto_kx_seedbytes())
public typealias PublicKey = Data
public typealias SecretKey = Data
public struct KeyPair {
public let publicKey: PublicKey
public let secretKey: SecretKey
public init(publicKey: PublicKey, secretKey: SecretKey) {
self.publicKey = publicKey
self.secretKey = secretKey
}
}
public struct SessionKeyPair {
public let rx: Data
public let tx: Data
public init(rx: Data, tx: Data) {
self.rx = rx
self.tx = tx
}
}
public enum Side {
case client
case server
case CLIENT
case SERVER
}
/**
Generates a key exchange secret key and a corresponding public key.
- Returns: A key pair containing the secret key and public key.
*/
public func keyPair() -> KeyPair? {
var publicKey = Data(count: PublicKeyBytes)
var secretKey = Data(count: SecretKeyBytes)
var result: Int32 = -1
result = publicKey.withUnsafeMutableBytes { publicKeyPtr in
return secretKey.withUnsafeMutableBytes { secretKeyPtr in
return crypto_kx_keypair(publicKeyPtr, secretKeyPtr)
let result = publicKey.withUnsafeMutableBytes { publicKeyPtr in
secretKey.withUnsafeMutableBytes { secretKeyPtr in
crypto_kx_keypair(publicKeyPtr, secretKeyPtr)
}
}
guard result == 0 else {
return nil
}
return KeyPair(publicKey: publicKey, secretKey: secretKey)
}
/**
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.
- Returns: A key pair containing the secret key and public key.
*/
public func keyPair(seed: Data) -> KeyPair? {
if seed.count != SeedBytes {
return nil
}
var pk = Data(count: PublicKeyBytes)
var sk = Data(count: SecretKeyBytes)
let result = pk.withUnsafeMutableBytes { pkPtr in
return sk.withUnsafeMutableBytes { skPtr in
return seed.withUnsafeBytes { seedPtr in
return crypto_kx_seed_keypair(pkPtr, skPtr, seedPtr)
sk.withUnsafeMutableBytes { skPtr in
seed.withUnsafeBytes { seedPtr in
crypto_kx_seed_keypair(pkPtr, skPtr, seedPtr)
}
}
}
if result != 0 {
return nil
}
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.
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 secretKey: The secret key to used 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
- 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.
*/
public func sessionKeyPair(publicKey: PublicKey, secretKey: SecretKey, otherPublicKey: PublicKey, side: Side) -> SessionKeyPair? {
if publicKey.count != PublicKeyBytes ||
secretKey.count != SecretKeyBytes ||
otherPublicKey.count != PublicKeyBytes {
return nil
}
var rx = 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
return tx.withUnsafeMutableBytes { txPtr in
return secretKey.withUnsafeBytes { secretKeyPtr in
return publicKey.withUnsafeBytes { publicKeyPtr in
return otherPublicKey.withUnsafeBytes { otherPublicKeyPtr in
return session_keys(rxPtr, txPtr, publicKeyPtr, secretKeyPtr, otherPublicKeyPtr)
tx.withUnsafeMutableBytes { txPtr in
secretKey.withUnsafeBytes { secretKeyPtr in
publicKey.withUnsafeBytes { publicKeyPtr in
otherPublicKey.withUnsafeBytes { otherPublicKeyPtr in
session_keys(rxPtr, txPtr, publicKeyPtr, secretKeyPtr, otherPublicKeyPtr)
}
}
}
}
}
if result != 0 {
return nil
}
return SessionKeyPair(rx: rx, tx: tx)
}
}

View File

@ -2,9 +2,6 @@
// PWHash.swift
// Sodium
//
// Created by Frank Denis on 4/29/15.
// Copyright (c) 2015 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
@ -19,77 +16,70 @@ public class PWHash {
public let MemLimitInteractive = Int(crypto_pwhash_memlimit_interactive())
public let MemLimitModerate = Int(crypto_pwhash_memlimit_moderate())
public let MemLimitSensitive = Int(crypto_pwhash_memlimit_sensitive())
public enum Alg {
case Default
case Argon2I13
case Argon2ID13
}
/**
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 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 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 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.
- Returns: The generated string.
*/
public func str(passwd: Data, opsLimit: Int, memLimit: Int) -> String? {
var output = Data(count: StrBytes)
let result = output.withUnsafeMutableBytes { outputPtr in
return passwd.withUnsafeBytes { passwdPtr in
return crypto_pwhash_str(outputPtr,
passwdPtr,
CUnsignedLongLong(passwd.count),
CUnsignedLongLong(opsLimit),
size_t(memLimit))
passwd.withUnsafeBytes { passwdPtr in
crypto_pwhash_str(outputPtr,
passwdPtr, CUnsignedLongLong(passwd.count),
CUnsignedLongLong(opsLimit), size_t(memLimit))
}
}
if result != 0 {
return nil
}
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`.
- Parameter hash: The password hash string to verify.
- Parameter passwd: The password data to verify.
- Returns: `true` if the verification succeeds.
*/
public func strVerify(hash: String, passwd: Data) -> Bool {
guard let hashData = (hash + "\0").data(using: .utf8, allowLossyConversion: false) else {
return false
}
return hashData.withUnsafeBytes { hashPtr in
return passwd.withUnsafeBytes { passwdPtr in
return crypto_pwhash_str_verify(
hashPtr,
passwdPtr,
CUnsignedLongLong(passwd.count)) == 0
passwd.withUnsafeBytes { passwdPtr in
crypto_pwhash_str_verify(
hashPtr, 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 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.
- Returns: `true` if the password hash should be updated.
*/
public func strNeedsRehash(hash: String, opsLimit: Int, memLimit: Int) -> Bool {
@ -97,31 +87,29 @@ public class PWHash {
return true
}
return hashData.withUnsafeBytes { hashPtr in
return crypto_pwhash_str_needs_rehash(
hashPtr,
CUnsignedLongLong(opsLimit), size_t(memLimit)) != 0
crypto_pwhash_str_needs_rehash(
hashPtr, CUnsignedLongLong(opsLimit), size_t(memLimit)) != 0
}
}
/**
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.
- Parameter outputLength: Desired length of the derived key. Should be at least 16 (128 bits)
- Parameter passwd: The password data to hash.
- 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 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.
*/
public func hash(outputLength: Int, passwd: Data, salt: Data, opsLimit: Int, memLimit: Int, alg: Alg = .Default) -> Data? {
if salt.count != SaltBytes {
return nil
}
var output = Data(count: outputLength)
var algId: Int32
switch alg {
@ -133,9 +121,9 @@ public class PWHash {
algId = crypto_pwhash_alg_argon2id13()
}
let result = passwd.withUnsafeBytes { passwdPtr in
return salt.withUnsafeBytes { saltPtr in
return output.withUnsafeMutableBytes { outputPtr in
return crypto_pwhash(
salt.withUnsafeBytes { saltPtr in
output.withUnsafeMutableBytes { outputPtr in
crypto_pwhash(
outputPtr, CUnsignedLongLong(outputLength),
passwdPtr, CUnsignedLongLong(passwd.count),
saltPtr, CUnsignedLongLong(opsLimit),
@ -143,11 +131,9 @@ public class PWHash {
}
}
}
if result != 0 {
return nil
}
return output
}
}

View File

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

View File

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

View File

@ -2,16 +2,13 @@
// SecretStream.swift
// Sodium_iOS
//
// Created by Frank Denis on 9/21/17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
public class SecretStream {
public let xchacha20poly1305 = XChaCha20Poly1305()
public class XChaCha20Poly1305 {
public static let ABytes = Int(crypto_secretstream_xchacha20poly1305_abytes())
public static let HeaderBytes = Int(crypto_secretstream_xchacha20poly1305_headerbytes())
@ -24,10 +21,10 @@ public class SecretStream {
}
public typealias Key = Data
public typealias Header = Data
/**
Generates a secret key.
- Returns: The generated key.
*/
public func key() -> Key? {
@ -37,25 +34,41 @@ public class SecretStream {
}
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? {
guard let stream = PushStream(secretKey: secretKey) else {
return nil
}
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? {
guard let stream = PullStream(secretKey: secretKey, header: header) else {
return nil
}
return stream
}
public class PushStream {
private var state: UnsafeMutablePointer<crypto_secretstream_xchacha20poly1305_state>?
private var _header: Header
init?(secretKey: Key) {
if secretKey.count != KeyBytes {
return nil
@ -75,20 +88,34 @@ public class SecretStream {
return nil
}
}
/**
The header of the stream, required to decrypt it.
- Returns: The stream header.
*/
public func header() -> 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)
if ad != nil {
_ad = ad!
}
let adx = Data(count:0)
var cipherText = Data(count: message.count + ABytes)
let result = cipherText.withUnsafeMutableBytes { cipherTextPtr in
adx.withUnsafeBytes { adPtr in
_ad.withUnsafeBytes { adPtr in
message.withUnsafeBytes { messagePtr in
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
}
/**
Performs an explicit key rotation.
*/
public func rekey() {
crypto_secretstream_xchacha20poly1305_rekey(state)
}
deinit {
guard let state = state else {
return
@ -112,10 +142,10 @@ public class SecretStream {
rawState.deallocate(capacity: 1)
}
}
public class PullStream {
private var state: UnsafeMutablePointer<crypto_secretstream_xchacha20poly1305_state>?
init?(secretKey: Key, header: Header) {
if header.count != HeaderBytes || secretKey.count != KeyBytes {
return nil
@ -134,7 +164,15 @@ public class SecretStream {
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)? {
if cipherText.count < ABytes {
return nil
@ -162,11 +200,14 @@ public class SecretStream {
}
return (message, tag)
}
/**
Performs an explicit key rotation.
*/
public func rekey() {
crypto_secretstream_xchacha20poly1305_rekey(state)
}
deinit {
guard let state = state else {
return

View File

@ -2,9 +2,6 @@
// ShortHash.swift
// Sodium
//
// Created by Frank Denis on 12/28/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
@ -12,12 +9,12 @@ import libsodium
public class ShortHash {
public let Bytes = Int(crypto_shorthash_bytes())
public let KeyBytes = Int(crypto_shorthash_keybytes())
public typealias Key = Data
/**
Generates a secret key.
- Returns: The generated key.
*/
public func key() -> Key? {
@ -27,34 +24,31 @@ public class ShortHash {
}
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.
- Parameter message: The data to be hashed.
- 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? {
if key.count != KeyBytes {
return nil
}
var output = Data(count: Bytes)
let result = output.withUnsafeMutableBytes { outputPtr in
return message.withUnsafeBytes { messagePtr in
return key.withUnsafeBytes { keyPtr in
return crypto_shorthash(outputPtr, messagePtr, CUnsignedLongLong(message.count), keyPtr)
message.withUnsafeBytes { messagePtr in
key.withUnsafeBytes { keyPtr in
crypto_shorthash(outputPtr, messagePtr, CUnsignedLongLong(message.count), keyPtr)
}
}
}
if result != 0 {
return nil
}
return output
}
}

View File

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

View File

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

View File

@ -2,9 +2,6 @@
// Stream.swift
// Sodium
//
// Created by Frank Denis on 5/30/17.
// Copyright © 2017 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
@ -13,13 +10,13 @@ public class Stream {
public let KeyBytes = Int(crypto_secretbox_keybytes())
public let NonceBytes = Int(crypto_secretbox_noncebytes())
public let Primitive = String.init(validatingUTF8: crypto_stream_primitive())
public typealias Key = Data
public typealias Nonce = Data
/**
Generates a secret key.
- Returns: The generated key.
*/
public func key() -> Key? {
@ -29,10 +26,10 @@ public class Stream {
}
return k
}
/**
Generates a random nonce.
- Returns: The generated nonce.
*/
public func nonce() -> Nonce {
@ -42,14 +39,18 @@ public class Stream {
}
return 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.
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 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)
*/
public func xor(input: Data, nonce: Nonce, secretKey: Key) -> Data? {
@ -59,28 +60,30 @@ public class Stream {
var output = Data(count: input.count)
let result = output.withUnsafeMutableBytes { outputPtr in
input.withUnsafeBytes { inputPtr in
return nonce.withUnsafeBytes { noncePtr in
return secretKey.withUnsafeBytes { secretKeyPtr in
return crypto_stream_xor(outputPtr, inputPtr, UInt64(input.count), noncePtr, secretKeyPtr)
nonce.withUnsafeBytes { noncePtr in
secretKey.withUnsafeBytes { secretKeyPtr in
crypto_stream_xor(outputPtr, inputPtr, UInt64(input.count), noncePtr, secretKeyPtr)
}
}
}
}
if result != 0 {
return nil
}
return output
}
/**
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.
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 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)
*/
public func xor(input: Data, secretKey: Key) -> (output:Data, nonce: Nonce)? {

View File

@ -2,18 +2,14 @@
// Utils.swift
// Sodium
//
// Created by Frank Denis on 12/27/14.
// Copyright (c) 2014 Frank Denis. All rights reserved.
//
import Foundation
import libsodium
public class Utils {
/**
Tries to effectively zero bytes in `data`, even if optimizations are being applied to the code.
- Parameter data: The `Data` object to zero.
*/
public func zero(_ data: inout Data) {
@ -21,174 +17,166 @@ public class Utils {
data.withUnsafeMutableBytes { (dataPtr: UnsafeMutablePointer<UInt8>) in
let rawPtr = UnsafeMutableRawPointer(dataPtr)
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.
*/
public func equals(_ b1: Data, _ b2: Data) -> Bool {
if b1.count != b2.count {
return false
}
return b1.withUnsafeBytes { b1Ptr in
return b2.withUnsafeBytes { b2Ptr in
return Int(sodium_memcmp(
UnsafeRawPointer(b1Ptr),
UnsafeRawPointer(b2Ptr),
b1.count)) == 0
b2.withUnsafeBytes { b2Ptr in
Int(sodium_memcmp(
UnsafeRawPointer(b1Ptr), 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? {
if b1.count != b2.count {
return nil
}
return b1.withUnsafeBytes { b1Ptr in
return b2.withUnsafeBytes { b2Ptr in
return Int(sodium_compare(
b1Ptr,
b2Ptr,
b1.count))
b2.withUnsafeBytes { b2Ptr in
Int(sodium_compare(
b1Ptr, b2Ptr, b1.count))
}
}
}
/**
Converts bytes stored in `bin` into a hexadecimal string.
- Parameter bin: The data to encode as hexdecimal.
- Returns: The encoded hexdecimal string.
*/
public func bin2hex(_ bin: Data) -> String? {
var hexData = Data(count: bin.count * 2 + 1)
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 {
return nil
}
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 ignore: Optional string containing readability characters to ignore during decoding.
- Returns: The decoded data.
*/
public func hex2bin(_ hex: String, ignore: String? = nil) -> Data? {
guard let hexData = hex.data(using: .utf8, allowLossyConversion: false) else {
return nil
}
let hexDataLen = hexData.count
let binDataCapacity = hexDataLen / 2
var binData = Data(count: binDataCapacity)
var binDataLen: size_t = 0
let ignore_cstr = ignore != nil ? (ignore! as NSString).utf8String : nil
let result = binData.withUnsafeMutableBytes { binPtr in
return hexData.withUnsafeBytes { hexPtr in
return sodium_hex2bin(binPtr,
binDataCapacity,
hexPtr,
hexDataLen,
ignore_cstr,
&binDataLen,
nil)
hexData.withUnsafeBytes { hexPtr in
sodium_hex2bin(binPtr, binDataCapacity,
hexPtr, hexDataLen,
ignore_cstr, &binDataLen, nil)
}
}
if result != 0 {
if result != 0 {
return nil
}
binData.count = Int(binDataLen)
return binData
}
public enum Base64Variant: CInt {
case ORIGINAL = 1
case ORIGINAL_NO_PADDING = 3
case URLSAFE = 5
case URLSAFE_NO_PADDING = 7
}
/**
Converts bytes stored in `bin` into a Base64 representation.
- Parameter bin: The data to encode as Base64.
- Parameter variant: the Base64 variant to use. By default: URLSAFE.
- 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))
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 {
return nil
}
}
return String.init(validatingUTF8: b64Ptr)
}
}
}
/*
Decode as a base64 string, ignoring characters included for readability.
- Parameter b64: The base64 string to decode.
Decodes a Base64 string, ignoring characters included for readability.
- Parameter b64: The Base64 string to decode.
- Parameter ignore: Optional string containing readability characters to ignore during decoding.
- 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 {
return nil
}
let b64DataLen = b64Data.count
let binDataCapacity = b64DataLen * 3 / 4
var binData = Data(count: binDataCapacity)
var binDataLen: size_t = 0
let ignore_cstr = ignore != nil ? (ignore! as NSString).utf8String : nil
let result = binData.withUnsafeMutableBytes { binPtr in
b64Data.withUnsafeBytes { b64Ptr in
sodium_base642bin(binPtr,
binDataCapacity,
b64Ptr,
b64DataLen,
ignore_cstr,
&binDataLen,
nil, variant.rawValue)
sodium_base642bin(binPtr, binDataCapacity,
b64Ptr, b64DataLen,
ignore_cstr, &binDataLen, nil, variant.rawValue)
}
}
if result != 0 {
return nil
}
binData.count = Int(binDataLen)
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 blocksize: the block size
*/
@ -204,13 +192,13 @@ public class Utils {
return nil
}
data.count = Int(paddedLen)
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 blocksize: the block size
*/
@ -223,7 +211,7 @@ public class Utils {
return nil
}
data.count = Int(unpaddedLen)
return ()
}
}

View File

@ -223,8 +223,7 @@ class ReadmeTests : XCTestCase {
let header = stream_enc.header()
let encrypted1 = stream_enc.push(message: message1)!
let encrypted2 = stream_enc.push(message: message2)!
let encrypted3 = stream_enc.push(message: message3,
tag: SecretStream.XChaCha20Poly1305.Tag.FINAL)!
let encrypted3 = stream_enc.push(message: message3, tag: .FINAL)!
/* stream decryption */
@ -236,19 +235,19 @@ class ReadmeTests : XCTestCase {
XCTAssertEqual(message1, message1_dec)
XCTAssertEqual(message2, message2_dec)
XCTAssertEqual(message3, message3_dec)
XCTAssertEqual(tag1, SecretStream.XChaCha20Poly1305.Tag.MESSAGE)
XCTAssertEqual(tag2, SecretStream.XChaCha20Poly1305.Tag.MESSAGE)
XCTAssertEqual(tag3, SecretStream.XChaCha20Poly1305.Tag.FINAL)
XCTAssertEqual(tag1, .MESSAGE)
XCTAssertEqual(tag2, .MESSAGE)
XCTAssertEqual(tag3, .FINAL)
}
func testBase64() {
let sodium = Sodium()
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 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(data2, "data".toData())

View File

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