File: ChaCha20CTR.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (118 lines) | stat: -rw-r--r-- 4,506 bytes parent folder | download
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)
        }
    }
}