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 119
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2021 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
//
//===----------------------------------------------------------------------===//
#if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
@_exported import CryptoKit
#else
@_implementationOnly import CCryptoBoringSSL
import Foundation
enum BoringSSLAESWRAPImpl {
static func wrap(key: SymmetricKey, keyToWrap: SymmetricKey) throws -> Data {
// There's a flat 8-byte overhead to AES KeyWrap.
var output = Data(repeating: 0, count: keyToWrap.byteCount + 8)
let rc = try key.withUnsafeAESKEY(mode: .encrypting) { aesKey in
output.withUnsafeMutableBytes { outputPtr -> CInt in
// Memory bind is safe: we cannot alias the pointer here.
let outputPtr = outputPtr.bindMemory(to: UInt8.self)
return keyToWrap.withUnsafeBytes { keyToWrapPtr -> CInt in
// Memory bind is safe: we cannot alias the pointer here.
let keyToWrapPtr = keyToWrapPtr.bindMemory(to: UInt8.self)
return CCryptoBoringSSL_AES_wrap_key(
aesKey, nil, outputPtr.baseAddress, keyToWrapPtr.baseAddress, keyToWrapPtr.count
)
}
}
}
guard rc >= 0 else {
throw CryptoKitError.internalBoringSSLError()
}
// Assert our 8-byte overhead story was true.
assert(rc == keyToWrap.byteCount + 8)
return output.prefix(Int(rc))
}
static func unwrap<WrappedKey: DataProtocol>(key: SymmetricKey, wrappedKey: WrappedKey) throws -> SymmetricKey {
if wrappedKey.regions.count == 1 {
return try self.unwrap(key: key, contiguousWrappedKey: wrappedKey.regions.first!)
} else {
let contiguous = Data(wrappedKey)
return try self.unwrap(key: key, contiguousWrappedKey: contiguous)
}
}
private static func unwrap<WrappedKey: ContiguousBytes>(key: SymmetricKey, contiguousWrappedKey: WrappedKey) throws -> SymmetricKey {
let unwrapped = try contiguousWrappedKey.withUnsafeBytes { inPtr in
try [UInt8](unsafeUninitializedCapacity: inPtr.count) { outputPtr, count in
// Bind is safe: we cannot violate the aliasing rules here as we never call to arbitrary code.
let inPtr = inPtr.bindMemory(to: UInt8.self)
let rc = try key.withUnsafeAESKEY(mode: .decrypting) { aesKey in
CCryptoBoringSSL_AES_unwrap_key(
aesKey, nil, outputPtr.baseAddress, inPtr.baseAddress, inPtr.count
)
}
guard rc > 0 else {
throw CryptoKitError.internalBoringSSLError()
}
// Assert our 8-byte overhead story is true.
assert(rc == inPtr.count - 8)
count = Int(rc)
}
}
return SymmetricKey(data: unwrapped)
}
}
extension SymmetricKey {
fileprivate enum AESKeyMode {
case encrypting
case decrypting
}
fileprivate func withUnsafeAESKEY<ResultType>(mode: AESKeyMode, _ body: (UnsafePointer<AES_KEY>) throws -> ResultType) throws -> ResultType {
try self.withUnsafeBytes { bytesPointer in
// Bind is safe: cannot alias the pointer here.
let bytesPointer = bytesPointer.bindMemory(to: UInt8.self)
var aesKey = AES_KEY()
let bitsInKey = UInt32(bytesPointer.count * 8)
let rc: CInt
switch mode {
case .encrypting:
rc = CCryptoBoringSSL_AES_set_encrypt_key(
bytesPointer.baseAddress!, bitsInKey, &aesKey
)
case .decrypting:
rc = CCryptoBoringSSL_AES_set_decrypt_key(
bytesPointer.baseAddress!, bitsInKey, &aesKey
)
}
guard rc == 0 else {
throw CryptoKitError.internalBoringSSLError()
}
return try withUnsafePointer(to: aesKey) {
return try body($0)
}
}
}
}
#endif // CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
|