Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using GCM Nonce pattern for CBC, CFB, and CTR #261

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 0 additions & 51 deletions Sources/_CryptoExtras/AES/AES_CBC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,57 +141,6 @@ extension AES {
}
}

extension AES._CBC {
/// An initialization vector.
public struct IV: Sendable {
// AES CBC uses a 128-bit IV.
var ivBytes: (
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8
)

public init() {
var rng = SystemRandomNumberGenerator()
let (first, second) = (rng.next(), rng.next())

self.ivBytes = (
UInt8(truncatingIfNeeded: first),
UInt8(truncatingIfNeeded: first >> 8),
UInt8(truncatingIfNeeded: first >> 16),
UInt8(truncatingIfNeeded: first >> 24),
UInt8(truncatingIfNeeded: first >> 32),
UInt8(truncatingIfNeeded: first >> 40),
UInt8(truncatingIfNeeded: first >> 48),
UInt8(truncatingIfNeeded: first >> 56),
UInt8(truncatingIfNeeded: second),
UInt8(truncatingIfNeeded: second >> 8),
UInt8(truncatingIfNeeded: second >> 16),
UInt8(truncatingIfNeeded: second >> 24),
UInt8(truncatingIfNeeded: second >> 32),
UInt8(truncatingIfNeeded: second >> 40),
UInt8(truncatingIfNeeded: second >> 48),
UInt8(truncatingIfNeeded: second >> 56)
)
}

public init<IVBytes: Collection>(ivBytes: IVBytes) throws where IVBytes.Element == UInt8 {
// We support a 128-bit IV.
guard ivBytes.count == 16 else {
throw CryptoKitError.incorrectKeySize
}

self.ivBytes = (
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
)

withUnsafeMutableBytes(of: &self.ivBytes) { bytesPtr in
bytesPtr.copyBytes(from: ivBytes)
}
}
}
}

extension Data {
fileprivate mutating func trimPadding() throws {
guard let paddingBytes = self.last else {
Expand Down
30 changes: 2 additions & 28 deletions Sources/_CryptoExtras/AES/AES_CFB.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ typealias AESCFBImpl = OpenSSLAESCFBImpl

extension AES {
public enum _CFB {
static let nonceByteCount = 16

@inlinable
public static func encrypt<Plaintext: DataProtocol>(
_ plaintext: Plaintext,
Expand All @@ -41,31 +43,3 @@ extension AES {
}
}
}

extension AES._CFB {
public struct IV: Sendable {
// AES CFB uses a 128-bit IV.
private var ivBytes: (UInt64, UInt64)

public init() {
var rng = SystemRandomNumberGenerator()
self.ivBytes = (rng.next(), rng.next())
}

public init<IVBytes: Collection>(ivBytes: IVBytes) throws where IVBytes.Element == UInt8 {
guard ivBytes.count == 16 else {
throw CryptoKitError.incorrectParameterSize
}

self.ivBytes = (0, 0)

Swift.withUnsafeMutableBytes(of: &self.ivBytes) { bytesPtr in
bytesPtr.copyBytes(from: ivBytes)
}
}

mutating func withUnsafeMutableBytes<ReturnType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ReturnType) rethrows -> ReturnType {
return try Swift.withUnsafeMutableBytes(of: &self.ivBytes, body)
}
}
}
41 changes: 2 additions & 39 deletions Sources/_CryptoExtras/AES/AES_CTR.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import Foundation
typealias AESCTRImpl = OpenSSLAESCTRImpl

extension AES {

public enum _CTR {
static let nonceByteCount = 12

@inlinable
public static func encrypt<Plaintext: DataProtocol>(
_ plaintext: Plaintext,
Expand All @@ -42,41 +43,3 @@ extension AES {
}
}
}

extension AES._CTR {
public struct Nonce: Sendable {
// AES CTR uses a 128-bit counter. It's most usual to use a 96-bit nonce
// and a 32-bit counter at the end, so we support that specific mode of
// operation here.
private var nonceBytes: (
UInt64, UInt32, UInt32
)

public init() {
var rng = SystemRandomNumberGenerator()
self.nonceBytes = (
rng.next(), rng.next(), rng.next()
)
}

public init<NonceBytes: Collection>(nonceBytes: NonceBytes) throws where NonceBytes.Element == UInt8 {
// We support a 96-bit nonce (with a 32-bit counter, initialized to 0) or a full 128-bit
// expression.
guard nonceBytes.count == 12 || nonceBytes.count == 16 else {
maschall marked this conversation as resolved.
Show resolved Hide resolved
throw CryptoKitError.incorrectParameterSize
}

self.nonceBytes = (
0, 0, 0
)

Swift.withUnsafeMutableBytes(of: &self.nonceBytes) { bytesPtr in
bytesPtr.copyBytes(from: nonceBytes)
}
}

mutating func withUnsafeMutableBytes<ReturnType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ReturnType) rethrows -> ReturnType {
return try Swift.withUnsafeMutableBytes(of: &self.nonceBytes, body)
}
}
}
9 changes: 7 additions & 2 deletions Sources/_CryptoExtras/AES/Block Function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,14 @@ extension AES {
init(_ blockBytes: BlockBytes) {
self.blockBytes = blockBytes
}

init(_ iv: AES._CBC.IV) {
self.blockBytes = iv.ivBytes
self.blockBytes = iv.bytes
}

init<BlockBytes: Sequence>(blockBytes: BlockBytes) where BlockBytes.Element == UInt8 {
let blockBytes: [UInt8] = Array(blockBytes)
self.init(blockBytes: blockBytes)
maschall marked this conversation as resolved.
Show resolved Hide resolved
}

init<BlockBytes: Collection>(blockBytes: BlockBytes) where BlockBytes.Element == UInt8 {
Expand Down
Loading