File: AESWrap_boring.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 (119 lines) | stat: -rw-r--r-- 4,625 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
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