1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftCrypto project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.md for the list of SwiftCrypto project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
@_implementationOnly import CCryptoBoringSSL
@_implementationOnly import CCryptoBoringSSLShims
import Crypto
@_implementationOnly import CryptoBoringWrapper
import Foundation
typealias ChaCha20CTRImpl = OpenSSLChaCha20CTRImpl
extension Insecure {
/// ChaCha20-CTR with 96-bit nonces and a 32 bit counter.
public enum ChaCha20CTR {
static let keyBitsCount = 256
static let nonceByteCount = 12
static let counterByteCount = 4
/// Encrypts data using ChaCha20CTR
///
/// - Parameters:
/// - message: The message to encrypt
/// - key: A 256-bit encryption key
/// - counter: A 4 byte counter (UInt32), defaults to 0
/// - nonce: A 12 byte nonce for ChaCha20 encryption. The nonce must be unique for every use of the key to seal data.
/// - Returns: The encrypted ciphertext
/// - Throws: CipherError errors
/// - Warning: You most likely want to use the ChaChaPoly implementation with AuthenticatedData available at `Crypto.ChaChaPoly`
public static func encrypt<
Plaintext: DataProtocol
>(
_ message: Plaintext,
using key: SymmetricKey,
counter: Insecure.ChaCha20CTR.Counter = Counter(),
nonce: Insecure.ChaCha20CTR.Nonce
) throws -> Data {
return try ChaCha20CTRImpl.encrypt(key: key, message: message, counter: counter.counter, nonce: nonce.bytes)
}
}
}
extension Insecure.ChaCha20CTR {
public struct Nonce: ContiguousBytes, Sequence {
let bytes: Data
/// Generates a fresh random Nonce. Unless required by a specification to provide a specific Nonce, this is the recommended initializer.
public init() {
var data = Data(repeating: 0, count: Insecure.ChaCha20CTR.nonceByteCount)
data.withUnsafeMutableBytes {
assert($0.count == Insecure.ChaCha20CTR.nonceByteCount)
$0.initializeWithRandomBytes(count: Insecure.ChaCha20CTR.nonceByteCount)
}
self.bytes = data
}
public init<D: DataProtocol>(data: D) throws {
if data.count != Insecure.ChaCha20CTR.nonceByteCount {
throw CryptoKitError.incorrectParameterSize
}
self.bytes = Data(data)
}
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
return try self.bytes.withUnsafeBytes(body)
}
public func makeIterator() -> Array<UInt8>.Iterator {
self.withUnsafeBytes({ buffPtr in
Array(buffPtr).makeIterator()
})
}
}
public struct Counter: ContiguousBytes {
let counter: UInt32
/// Generates a fresh Counter set to 0. Unless required by a specification to provide a specific Counter, this is the recommended initializer.
public init() {
self.counter = 0
}
/// Explicitly set the Counter's offset using a byte sequence
public init<D: DataProtocol>(data: D) throws {
if data.count != Insecure.ChaCha20CTR.counterByteCount {
throw CryptoKitError.incorrectParameterSize
}
let startIndex = data.startIndex
self.counter = (
(UInt32(data[data.index(startIndex, offsetBy: 0)]) << 0) |
(UInt32(data[data.index(startIndex, offsetBy: 1)]) << 8) |
(UInt32(data[data.index(startIndex, offsetBy: 2)]) << 16) |
(UInt32(data[data.index(startIndex, offsetBy: 3)]) << 24)
)
}
/// Explicitly set the Counter's offset using a UInt32
public init(offset: UInt32) throws {
self.counter = offset
}
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
return try Swift.withUnsafeBytes(of: self.counter, body)
}
}
}
|