File: secpECDH_Runner_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 (141 lines) | stat: -rw-r--r-- 6,711 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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftCrypto open source project
//
// Copyright (c) 2019 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
//
//===----------------------------------------------------------------------===//
import Foundation
import XCTest

#if CRYPTO_IN_SWIFTPM && !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
// Skip tests that require @testable imports of CryptoKit.
#else
#if !CRYPTO_IN_SWIFTPM_FORCE_BUILD_API
@testable import CryptoKit
#else
@_implementationOnly import CCryptoBoringSSL
@testable import Crypto
#endif

extension NISTECDHTests {
    func testGroupOpenSSL<PrivKey: NISTECPrivateKey & DiffieHellmanKeyAgreement, Curve: OpenSSLSupportedNISTCurve>(group: ECDHTestGroup, privateKeys: PrivKey.Type, onCurve curve: Curve.Type, file: StaticString = #file, line: UInt = #line) {
        for testVector in group.tests {
            do {
                let pkBytes = try Array(hexString: testVector.publicKey)
                let publicKey = try PrivKey.PK(derBytes: pkBytes, curve: Curve.self)

                var privateBytes = [UInt8]()
                privateBytes = try padKeyIfNecessary(curve: curve, vector: testVector.privateKey)

                let privateKey = try PrivKey(rawRepresentation: privateBytes)

                let agreement = try unwrap(publicKey as? PrivKey.PublicKey, file: file, line: line)
                let result = try privateKey.sharedSecretFromKeyAgreement(with: agreement)

                let expectedResult = try Array(hexString: testVector.shared)

                XCTAssertEqual(Array(result.ss), Array(expectedResult), file: file, line: line)
            } catch ECDHTestErrors.PublicKeyFailure {
                XCTAssert(testVector.flags.contains("CompressedPoint") || testVector.result == "invalid" || testVector.flags.contains("InvalidPublic") || testVector.flags.contains("InvalidAsn"), file: file, line: line)
            } catch ECDHTestErrors.ParseSPKIFailure {
                XCTAssert(testVector.flags.contains("InvalidAsn") || testVector.flags.contains("UnnamedCurve"), file: file, line: line)
            } catch {
                if testVector.result == "valid" {
                    XCTAssert(testVector.tcId == 31 || testVector.tcId == 20 || testVector.tcId == 25, file: file, line: line)
                }
            }
        }
    }

    func testGroupPointOpenSSL<PrivKey: NISTECPrivateKey & DiffieHellmanKeyAgreement, Curve: OpenSSLSupportedNISTCurve>(group: ECDHTestGroup, privateKeys: PrivKey.Type, onCurve curve: Curve.Type, file: StaticString = #file, line: UInt = #line) {
        for testVector in group.tests {
            do {
                let pkBytes = try Array(hexString: testVector.publicKey)
                let publicKey: PrivKey.PK

                if testVector.flags.contains("CompressedPoint") {
                    publicKey = try PrivKey.PK(compressedRepresentation: pkBytes)
                } else {
                    publicKey = try PrivKey.PK(x963Representation: pkBytes)
                }

                var privateBytes = [UInt8]()
                privateBytes = try padKeyIfNecessary(curve: curve, vector: testVector.privateKey)

                let privateKey = try PrivKey(rawRepresentation: privateBytes)

                let agreement = try unwrap(publicKey as? PrivKey.PublicKey, file: file, line: line)
                let result = try privateKey.sharedSecretFromKeyAgreement(with: agreement)

                let expectedResult = try Array(hexString: testVector.shared)

                XCTAssertEqual(Array(result.ss), Array(expectedResult), file: file, line: line)

                // If we didn't throw here, assert that the test is not invalid
                XCTAssertTrue(testVector.result == "valid" || testVector.result == "acceptable")
            } catch {
                XCTAssertEqual(testVector.result, "invalid")
            }
        }
    }

    private func padKeyIfNecessary<Curve: OpenSSLSupportedNISTCurve>(curve: Curve.Type, vector: String, file: StaticString = #file, line: UInt = #line) throws -> [UInt8] {
        // There are a few edge cases here.
        //
        // First, our raw bytes function requires the
        // input buffer to be exactly as long as the curve size.
        //
        // Second, Wycheproof inputs may be too short or too long with
        // leading zeros.
        let curveSize = curve.coordinateByteCount
        var privateBytes = [UInt8](repeating: 0, count: curveSize)

        let hexStringFromVector = (vector.count % 2 == 0) ? vector : "0\(vector)"
        let privateKeyVector = try! Array(hexString: hexStringFromVector)

        // Input is too long (i.e. we have leading zeros)
        if privateKeyVector.count > curveSize {
            privateBytes = privateKeyVector.suffix(curveSize)
        } else if privateKeyVector.count == curveSize {
            privateBytes = privateKeyVector
        } else {
            // Input is too short
            privateBytes.replaceSubrange((privateBytes.count - privateKeyVector.count) ..< privateBytes.count, with: privateKeyVector)
        }

        return privateBytes
    }
}

extension NISTECPublicKey {
    /// Creates the given EC public key using the DER encoding of the key.
    init<Curve: OpenSSLSupportedNISTCurve>(derBytes: [UInt8], curve: Curve.Type = Curve.self) throws {
        // Bad news everybody. Using the EC DER parsing from OpenSSL limits our ability to tell the difference
        // between an invalid SPKI layout (which we don't care about, as the production library doesn't support DER-encoded
        // EC keys) and a SPKI layout that is syntactically valid but doesn't represent a valid point on the curve. We _do_
        // care about passing this into the production library.
        //
        // This means we've only one option: we have to implement "just enough" ASN.1.
        var derBytes = derBytes[...]
        let spki = try ASN1SubjectPublicKeyInfo(fromASN1: &derBytes)
        guard derBytes.count == 0, spki.algorithm.algorithm == ASN1ObjectIdentifier.AlgorithmIdentifier.idEcPublicKey else {
            throw ECDHTestErrors.ParseSPKIFailure
        }

        // Ok, the bitstring we are holding is the X963 representation of the public key. Try to create it.
        do {
            try self.init(x963Representation: spki.subjectPublicKey)
        } catch {
            throw ECDHTestErrors.PublicKeyFailure
        }
    }
}

#endif // CRYPTO_IN_SWIFTPM