Skip to content

Commit bd46345

Browse files
committed
add implementation of AWS v4 Signer from aws-signer-v4 and HMAC+SHA256 from CryptoSwift
1 parent 9361bed commit bd46345

29 files changed

+2514
-8
lines changed

Package.swift

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,30 @@ let package = Package(
1414
products: [
1515
// this library exports `AWSLambdaRuntimeCore` and adds Foundation convenience methods
1616
.library(name: "AWSLambdaRuntime", targets: ["AWSLambdaRuntime"]),
17+
1718
// this has all the main functionality for lambda and it does not link Foundation
1819
.library(name: "AWSLambdaRuntimeCore", targets: ["AWSLambdaRuntimeCore"]),
20+
1921
// plugin to create a new Lambda function, based on a template
2022
.plugin(name: "AWSLambdaInitializer", targets: ["AWSLambdaInitializer"]),
23+
2124
// plugin to package the lambda, creating an archive that can be uploaded to AWS
2225
// requires Linux or at least macOS v15
2326
.plugin(name: "AWSLambdaPackager", targets: ["AWSLambdaPackager"]),
27+
2428
// plugin to deploy a Lambda function
25-
.plugin(name: "AWSLambdadeployer", targets: ["AWSLambdaDeployer"]),
26-
.executable(name: "AWSLambdaDeployerHelper", targets: ["AWSLambdaDeployerHelper"]),
29+
.plugin(name: "AWSLambdaDeployer", targets: ["AWSLambdaDeployer"]),
30+
31+
// an executable that implements the business logic for the plugins
32+
.executable(name: "AWSLambdaPluginHelper", targets: ["AWSLambdaPluginHelper"]),
33+
2734
// for testing only
2835
.library(name: "AWSLambdaTesting", targets: ["AWSLambdaTesting"]),
2936
],
3037
dependencies: [
3138
.package(url: "https://github.com/apple/swift-nio.git", from: "2.76.0"),
3239
.package(url: "https://github.com/apple/swift-log.git", from: "1.5.4"),
33-
.package(url: "https://github.com/apple/swift-crypto.git", from: "3.9.1"),
40+
// .package(url: "https://github.com/apple/swift-crypto.git", from: "3.9.1"),
3441
],
3542
targets: [
3643
.target(
@@ -96,15 +103,14 @@ let package = Package(
96103
]
97104
),
98105
dependencies: [
99-
.target(name: "AWSLambdaDeployerHelper")
106+
.target(name: "AWSLambdaPluginHelper")
100107
]
101108
),
102109
.executableTarget(
103-
name: "AWSLambdaDeployerHelper",
110+
name: "AWSLambdaPluginHelper",
104111
dependencies: [
105112
.product(name: "NIOHTTP1", package: "swift-nio"),
106113
.product(name: "NIOCore", package: "swift-nio"),
107-
.product(name: "Crypto", package: "swift-crypto"),
108114
],
109115
swiftSettings: [.swiftLanguageMode(.v6)]
110116
),
@@ -148,5 +154,12 @@ let package = Package(
148154
],
149155
swiftSettings: [.swiftLanguageMode(.v5)]
150156
),
157+
.testTarget(
158+
name: "AWSLambdaPluginHelperTests",
159+
dependencies: [
160+
.byName(name: "AWSLambdaPluginHelper")
161+
]
162+
),
163+
151164
]
152165
)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the SwiftAWSLambdaRuntime open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the SwiftAWSLambdaRuntime project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of SwiftAWSLambdaRuntime project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#if canImport(FoundationEssentials)
16+
import FoundationEssentials
17+
#else
18+
import Foundation
19+
#endif
20+
21+
// extension Array where Element == UInt8 {
22+
// public var base64: String {
23+
// Data(self).base64EncodedString()
24+
// }
25+
// }
26+
27+
extension Data {
28+
var bytes: [UInt8] {
29+
return [UInt8](self)
30+
}
31+
}
32+
33+
extension String {
34+
public var array: [UInt8] {
35+
Array(self.utf8)
36+
}
37+
}
38+
39+
extension HMAC {
40+
public static func authenticate(for data: [UInt8], using key: [UInt8], variant: HMAC.Variant = .sha2(.sha256)) throws -> [UInt8] {
41+
let authenticator = HMAC(key: key, variant: variant)
42+
return try authenticator.authenticate(data)
43+
}
44+
public static func authenticate(for data: Data, using key: [UInt8], variant: HMAC.Variant = .sha2(.sha256)) throws -> [UInt8] {
45+
let authenticator = HMAC(key: key, variant: variant)
46+
return try authenticator.authenticate(data.bytes)
47+
}
48+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//
2+
// CryptoSwift
3+
//
4+
// Copyright (C) 2014-2022 Marcin Krzyżanowski <[email protected]>
5+
// This software is provided 'as-is', without any express or implied warranty.
6+
//
7+
// In no event will the authors be held liable for any damages arising from the use of this software.
8+
//
9+
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
10+
//
11+
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
12+
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13+
// - This notice may not be removed or altered from any source or binary distribution.
14+
//
15+
16+
extension Array {
17+
@inlinable
18+
init(reserveCapacity: Int) {
19+
self = Array<Element>()
20+
self.reserveCapacity(reserveCapacity)
21+
}
22+
23+
@inlinable
24+
var slice: ArraySlice<Element> {
25+
self[self.startIndex ..< self.endIndex]
26+
}
27+
28+
@inlinable
29+
subscript (safe index: Index) -> Element? {
30+
return indices.contains(index) ? self[index] : nil
31+
}
32+
}
33+
34+
extension Array where Element == UInt8 {
35+
public init(hex: String) {
36+
self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount)
37+
var buffer: UInt8?
38+
var skip = hex.hasPrefix("0x") ? 2 : 0
39+
for char in hex.unicodeScalars.lazy {
40+
guard skip == 0 else {
41+
skip -= 1
42+
continue
43+
}
44+
guard char.value >= 48 && char.value <= 102 else {
45+
removeAll()
46+
return
47+
}
48+
let v: UInt8
49+
let c: UInt8 = UInt8(char.value)
50+
switch c {
51+
case let c where c <= 57:
52+
v = c - 48
53+
case let c where c >= 65 && c <= 70:
54+
v = c - 55
55+
case let c where c >= 97:
56+
v = c - 87
57+
default:
58+
removeAll()
59+
return
60+
}
61+
if let b = buffer {
62+
append(b << 4 | v)
63+
buffer = nil
64+
} else {
65+
buffer = v
66+
}
67+
}
68+
if let b = buffer {
69+
append(b)
70+
}
71+
}
72+
73+
public func toHexString() -> String {
74+
`lazy`.reduce(into: "") {
75+
var s = String($1, radix: 16)
76+
if s.count == 1 {
77+
s = "0" + s
78+
}
79+
$0 += s
80+
}
81+
}
82+
}
83+
84+
extension Array where Element == UInt8 {
85+
/// split in chunks with given chunk size
86+
@available(*, deprecated)
87+
public func chunks(size chunksize: Int) -> Array<Array<Element>> {
88+
var words = Array<Array<Element>>()
89+
words.reserveCapacity(count / chunksize)
90+
for idx in stride(from: chunksize, through: count, by: chunksize) {
91+
words.append(Array(self[idx - chunksize ..< idx])) // slow for large table
92+
}
93+
let remainder = suffix(count % chunksize)
94+
if !remainder.isEmpty {
95+
words.append(Array(remainder))
96+
}
97+
return words
98+
}
99+
100+
// public func md5() -> [Element] {
101+
// Digest.md5(self)
102+
// }
103+
104+
// public func sha1() -> [Element] {
105+
// Digest.sha1(self)
106+
// }
107+
108+
// public func sha224() -> [Element] {
109+
// Digest.sha224(self)
110+
// }
111+
112+
public func sha256() -> [Element] {
113+
Digest.sha256(self)
114+
}
115+
116+
public func sha384() -> [Element] {
117+
Digest.sha384(self)
118+
}
119+
120+
public func sha512() -> [Element] {
121+
Digest.sha512(self)
122+
}
123+
124+
public func sha2(_ variant: SHA2.Variant) -> [Element] {
125+
Digest.sha2(self, variant: variant)
126+
}
127+
128+
public func sha3(_ variant: SHA3.Variant) -> [Element] {
129+
Digest.sha3(self, variant: variant)
130+
}
131+
132+
// public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
133+
// Checksum.crc32(self, seed: seed, reflect: reflect)
134+
// }
135+
136+
// public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
137+
// Checksum.crc32c(self, seed: seed, reflect: reflect)
138+
// }
139+
140+
// public func crc16(seed: UInt16? = nil) -> UInt16 {
141+
// Checksum.crc16(self, seed: seed)
142+
// }
143+
144+
// public func encrypt(cipher: Cipher) throws -> [Element] {
145+
// try cipher.encrypt(self.slice)
146+
// }
147+
148+
// public func decrypt(cipher: Cipher) throws -> [Element] {
149+
// try cipher.decrypt(self.slice)
150+
// }
151+
152+
public func authenticate<A: Authenticator>(with authenticator: A) throws -> [Element] {
153+
try authenticator.authenticate(self)
154+
}
155+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//
2+
// CryptoSwift
3+
//
4+
// Copyright (C) 2014-2022 Marcin Krzyżanowski <[email protected]>
5+
// This software is provided 'as-is', without any express or implied warranty.
6+
//
7+
// In no event will the authors be held liable for any damages arising from the use of this software.
8+
//
9+
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
10+
//
11+
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
12+
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13+
// - This notice may not be removed or altered from any source or binary distribution.
14+
//
15+
16+
/// Message authentication code.
17+
public protocol Authenticator {
18+
/// Calculate Message Authentication Code (MAC) for message.
19+
func authenticate(_ bytes: Array<UInt8>) throws -> Array<UInt8>
20+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//
2+
// CryptoSwift
3+
//
4+
// Copyright (C) 2014-2022 Marcin Krzyżanowski <[email protected]>
5+
// This software is provided 'as-is', without any express or implied warranty.
6+
//
7+
// In no event will the authors be held liable for any damages arising from the use of this software.
8+
//
9+
// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
10+
//
11+
// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
12+
// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13+
// - This notice may not be removed or altered from any source or binary distribution.
14+
//
15+
16+
@usableFromInline
17+
struct BatchedCollectionIndex<Base: Collection> {
18+
let range: Range<Base.Index>
19+
}
20+
21+
extension BatchedCollectionIndex: Comparable {
22+
@usableFromInline
23+
static func == <BaseCollection>(lhs: BatchedCollectionIndex<BaseCollection>, rhs: BatchedCollectionIndex<BaseCollection>) -> Bool {
24+
lhs.range.lowerBound == rhs.range.lowerBound
25+
}
26+
27+
@usableFromInline
28+
static func < <BaseCollection>(lhs: BatchedCollectionIndex<BaseCollection>, rhs: BatchedCollectionIndex<BaseCollection>) -> Bool {
29+
lhs.range.lowerBound < rhs.range.lowerBound
30+
}
31+
}
32+
33+
protocol BatchedCollectionType: Collection {
34+
associatedtype Base: Collection
35+
}
36+
37+
@usableFromInline
38+
struct BatchedCollection<Base: Collection>: Collection {
39+
let base: Base
40+
let size: Int
41+
42+
@usableFromInline
43+
init(base: Base, size: Int) {
44+
self.base = base
45+
self.size = size
46+
}
47+
48+
@usableFromInline
49+
typealias Index = BatchedCollectionIndex<Base>
50+
51+
private func nextBreak(after idx: Base.Index) -> Base.Index {
52+
self.base.index(idx, offsetBy: self.size, limitedBy: self.base.endIndex) ?? self.base.endIndex
53+
}
54+
55+
@usableFromInline
56+
var startIndex: Index {
57+
Index(range: self.base.startIndex..<self.nextBreak(after: self.base.startIndex))
58+
}
59+
60+
@usableFromInline
61+
var endIndex: Index {
62+
Index(range: self.base.endIndex..<self.base.endIndex)
63+
}
64+
65+
@usableFromInline
66+
func index(after idx: Index) -> Index {
67+
Index(range: idx.range.upperBound..<self.nextBreak(after: idx.range.upperBound))
68+
}
69+
70+
@usableFromInline
71+
subscript(idx: Index) -> Base.SubSequence {
72+
self.base[idx.range]
73+
}
74+
}
75+
76+
extension Collection {
77+
@inlinable
78+
func batched(by size: Int) -> BatchedCollection<Self> {
79+
BatchedCollection(base: self, size: size)
80+
}
81+
}

0 commit comments

Comments
 (0)