SwiftCrypto (#3)
* Use swift-crypto for hashing requirements * Remove swift 5.0 as it won't compile * Optimization - stop recreating DateFormatter * Ressurected AWSCrypto so we can support earlier OS versions * Update CI for workdir issue, remove libssl-dev
This commit is contained in:
parent
f28d6f6503
commit
b8af0b2a43
|
@ -10,21 +10,16 @@ jobs:
|
|||
uses: actions/checkout@v1
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Build
|
||||
run: swift build
|
||||
- name: Test
|
||||
- name: Build and Test
|
||||
run: swift test
|
||||
|
||||
linux:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
tag: ['5.0', '5.1']
|
||||
tag: ['5.1', '5.2']
|
||||
container:
|
||||
image: swift:${{ matrix.tag }}
|
||||
volumes:
|
||||
- $GITHUB_WORKSPACE:/src
|
||||
options: --workdir /src
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
|
@ -33,9 +28,7 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -q -y tzdata libssl-dev zlib1g-dev
|
||||
- name: Build
|
||||
run: swift build
|
||||
- name: Test
|
||||
apt-get install -q -y tzdata zlib1g-dev
|
||||
- name: Build and Test
|
||||
run: swift test
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
FROM swift:5.1 as builder
|
||||
FROM swift:5.2 as builder
|
||||
|
||||
RUN apt-get -qq update && apt-get install -y \
|
||||
libssl-dev zlib1g-dev \
|
||||
zlib1g-dev \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /aws-signer
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// swift-tools-version:5.0
|
||||
// swift-tools-version:5.1
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
@ -15,24 +15,22 @@ let package = Package(
|
|||
],
|
||||
targets: [
|
||||
.target(name: "AWSSigner", dependencies: ["AWSCrypto", "NIO", "NIOHTTP1"]),
|
||||
.target(name: "AWSCrypto", dependencies: ["CAWSCrypto"]),
|
||||
.target(name: "CAWSCrypto", dependencies: []),
|
||||
|
||||
.target(name: "AWSCrypto", dependencies: []),
|
||||
.target(name: "HTTPClientAWSSigner", dependencies: ["AWSSigner", "AsyncHTTPClient"]),
|
||||
|
||||
.testTarget(name: "AWSSignerTests", dependencies: ["AWSSigner", "HTTPClientAWSSigner"]),
|
||||
.testTarget(name: "AWSCryptoTests", dependencies: ["AWSCrypto"]),
|
||||
.testTarget(name: "AWSSignerTests", dependencies: ["AWSSigner", "HTTPClientAWSSigner"])
|
||||
]
|
||||
)
|
||||
|
||||
// switch for whether to use CAWSSigner to shim between OpenSSL versions
|
||||
// switch for whether to use swift crypto. Swift crypto requires macOS10.15 or iOS13.I'd rather not pass this requirement on
|
||||
#if os(Linux)
|
||||
let useOpenSSLShim = true
|
||||
let useSwiftCrypto = true
|
||||
#else
|
||||
let useOpenSSLShim = false
|
||||
let useSwiftCrypto = false
|
||||
#endif
|
||||
|
||||
// Decide on where we get our SSL support from. Linux usses NIOSSL to provide SSL. Linux also needs CAWSSDKOpenSSL to shim across different OpenSSL versions for the HMAC functions.
|
||||
if useOpenSSLShim {
|
||||
package.dependencies.append(.package(url: "https://github.com/apple/swift-nio-ssl-support.git", from: "1.0.0"))
|
||||
// Use Swift cypto on Linux.
|
||||
if useSwiftCrypto {
|
||||
package.dependencies.append(.package(url: "https://github.com/apple/swift-crypto.git", from: "1.0.0"))
|
||||
package.targets.first{$0.name == "AWSCrypto"}?.dependencies.append("Crypto")
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// ByteArray.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
#if !os(Linux)
|
||||
|
||||
import protocol Foundation.ContiguousBytes
|
||||
|
||||
/// Protocol for object encapsulating an array of bytes
|
||||
protocol ByteArray: Sequence, ContiguousBytes, CustomStringConvertible, Hashable where Element == UInt8 {
|
||||
protocol ByteArray: Sequence, ContiguousBytes, Hashable where Element == UInt8 {
|
||||
init(bytes: [UInt8])
|
||||
var bytes: [UInt8] { get set }
|
||||
}
|
||||
|
@ -21,10 +22,6 @@ extension ByteArray {
|
|||
public func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R {
|
||||
return try bytes.withUnsafeBytes(body)
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
// hex digest
|
||||
return bytes.map{String(format: "%02x", $0)}.joined()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
// Digest.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import protocol Foundation.ContiguousBytes
|
||||
|
||||
/// Protocol for Digest object returned from HashFunction
|
||||
public protocol Digest: Sequence, ContiguousBytes, CustomStringConvertible, Hashable where Element == UInt8 {
|
||||
public protocol Digest: Sequence, ContiguousBytes, Hashable where Element == UInt8 {
|
||||
static var byteCount: Int {get}
|
||||
}
|
||||
|
||||
/// Protocol for Digest object consisting of a byte array
|
||||
protocol ByteDigest: Digest, ByteArray { }
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// HMAC.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import CommonCrypto
|
||||
import protocol Foundation.DataProtocol
|
||||
|
||||
/// Hash Authentication Code returned by HMAC
|
||||
|
@ -8,10 +11,6 @@ public struct HashAuthenticationCode: ByteArray {
|
|||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
#if canImport(CommonCrypto)
|
||||
|
||||
import CommonCrypto
|
||||
|
||||
/// Object generating HMAC for data block given a symmetric key
|
||||
public struct HMAC<H: CCHashFunction> {
|
||||
|
||||
|
@ -66,63 +65,4 @@ extension HMAC {
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
import CAWSCrypto
|
||||
|
||||
public struct HMAC<H: OpenSSLHashFunction> {
|
||||
|
||||
let key: SymmetricKey
|
||||
var context: OpaquePointer
|
||||
|
||||
/// return authentication code for data block given a symmetric key
|
||||
public static func authenticationCode<D : DataProtocol>(for data: D, using key: SymmetricKey) -> HashAuthenticationCode {
|
||||
var hmac = HMAC(key: key)
|
||||
hmac.update(data: data)
|
||||
return hmac.finalize()
|
||||
}
|
||||
|
||||
/// update HMAC calculation with a block of data
|
||||
public mutating func update<D: DataProtocol>(data: D) {
|
||||
if let digest = data.withContiguousStorageIfAvailable({ bytes in
|
||||
return self.update(bufferPointer: bytes)
|
||||
}) {
|
||||
return digest
|
||||
} else {
|
||||
var buffer = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: data.count)
|
||||
data.copyBytes(to: buffer)
|
||||
defer { buffer.deallocate() }
|
||||
self.update(bufferPointer: .init(buffer))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension HMAC {
|
||||
/// initialize HMAC with symmetric key
|
||||
public init(key: SymmetricKey) {
|
||||
self.key = key
|
||||
self.context = AWSCRYPTO_HMAC_CTX_new()
|
||||
self.initialize()
|
||||
}
|
||||
|
||||
/// initialize HMAC calculation
|
||||
mutating func initialize() {
|
||||
HMAC_Init_ex(context, key.bytes, Int32(key.bytes.count), H.algorithm, nil)
|
||||
}
|
||||
|
||||
/// update HMAC calculation with a buffer
|
||||
mutating func update(bufferPointer: UnsafeBufferPointer<UInt8>) {
|
||||
HMAC_Update(context, bufferPointer.baseAddress, bufferPointer.count)
|
||||
}
|
||||
|
||||
/// finalize HMAC calculation and return authentication code
|
||||
public mutating func finalize() -> HashAuthenticationCode {
|
||||
var authenticationCode: [UInt8] = .init(repeating: 0, count: H.Digest.byteCount)
|
||||
var length: UInt32 = 0
|
||||
HMAC_Final(context, &authenticationCode, &length)
|
||||
AWSCRYPTO_HMAC_CTX_free(context)
|
||||
return .init(bytes: authenticationCode)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// HashFunction.swift
|
||||
// HashFunction protocol and OpenSSL, CommonCrypto specialisations
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import CommonCrypto
|
||||
import protocol Foundation.DataProtocol
|
||||
|
||||
/// Protocol for Hashing function
|
||||
|
@ -59,55 +61,10 @@ extension HashFunction {
|
|||
}
|
||||
}
|
||||
|
||||
#if canImport(CommonCrypto)
|
||||
|
||||
import CommonCrypto
|
||||
|
||||
/// public protocol for Common Crypto hash functions
|
||||
public protocol CCHashFunction: HashFunction {
|
||||
static var algorithm: CCHmacAlgorithm { get }
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
import CAWSCrypto
|
||||
|
||||
/// public protocol for OpenSSL hash function
|
||||
public protocol OpenSSLHashFunction: HashFunction {
|
||||
static var algorithm: OpaquePointer { get }
|
||||
}
|
||||
|
||||
/// internal protocol for OpenSSL hash functions that hides implementation details
|
||||
protocol _OpenSSLHashFunction: OpenSSLHashFunction where Digest: ByteDigest {
|
||||
var context: OpaquePointer { get set }
|
||||
init(context: OpaquePointer)
|
||||
}
|
||||
|
||||
extension _OpenSSLHashFunction {
|
||||
/// initialization
|
||||
public init() {
|
||||
self.init(context: AWSCRYPTO_EVP_MD_CTX_new())
|
||||
initialize()
|
||||
}
|
||||
|
||||
/// initialize hash function
|
||||
mutating func initialize() {
|
||||
EVP_DigestInit_ex(context, Self.algorithm, nil)
|
||||
}
|
||||
|
||||
/// update hash function with data
|
||||
public mutating func update(bufferPointer: UnsafeRawBufferPointer) {
|
||||
EVP_DigestUpdate(context, bufferPointer.baseAddress, bufferPointer.count)
|
||||
}
|
||||
|
||||
/// finalize hash function and return digest
|
||||
public mutating func finalize() -> Self.Digest {
|
||||
var digest: [UInt8] = .init(repeating: 0, count: Digest.byteCount)
|
||||
var count: UInt32 = 0
|
||||
EVP_DigestFinal_ex(context, &digest, &count)
|
||||
AWSCRYPTO_EVP_MD_CTX_free(context)
|
||||
return .init(bytes: .init(digest))
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// Insecure.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
public enum Insecure {}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// MD5.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
#if canImport(CommonCrypto)
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import CommonCrypto
|
||||
|
||||
|
@ -40,21 +40,4 @@ public extension Insecure {
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
import CAWSCrypto
|
||||
|
||||
public extension Insecure {
|
||||
struct MD5Digest : ByteDigest {
|
||||
public static var byteCount: Int { return Int(MD5_DIGEST_LENGTH) }
|
||||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
struct MD5: _OpenSSLHashFunction {
|
||||
public typealias Digest = MD5Digest
|
||||
public static var algorithm: OpaquePointer { return EVP_md5() }
|
||||
var context: OpaquePointer
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
// SHA1.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// written by AdamFowler 2020/01/30
|
||||
#if canImport(CommonCrypto)
|
||||
|
||||
import CommonCrypto
|
||||
|
||||
public extension Insecure {
|
||||
|
||||
struct SHA1Digest : ByteDigest {
|
||||
public static var byteCount: Int { return Int(CC_SHA1_DIGEST_LENGTH) }
|
||||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
struct SHA1: CCHashFunction {
|
||||
public typealias Digest = SHA1Digest
|
||||
public static var algorithm: CCHmacAlgorithm { return CCHmacAlgorithm(kCCHmacAlgSHA1) }
|
||||
var context: CC_SHA1_CTX
|
||||
|
||||
public static func hash(bufferPointer: UnsafeRawBufferPointer) -> Self.Digest {
|
||||
var digest: [UInt8] = .init(repeating: 0, count: Digest.byteCount)
|
||||
CC_SHA1(bufferPointer.baseAddress, CC_LONG(bufferPointer.count), &digest)
|
||||
return .init(bytes: digest)
|
||||
}
|
||||
|
||||
public init() {
|
||||
context = CC_SHA1_CTX()
|
||||
CC_SHA1_Init(&context)
|
||||
}
|
||||
|
||||
public mutating func update(bufferPointer: UnsafeRawBufferPointer) {
|
||||
CC_SHA1_Update(&context, bufferPointer.baseAddress, CC_LONG(bufferPointer.count))
|
||||
}
|
||||
|
||||
public mutating func finalize() -> Self.Digest {
|
||||
var digest: [UInt8] = .init(repeating: 0, count: Digest.byteCount)
|
||||
CC_SHA1_Final(&digest, &context)
|
||||
return .init(bytes: digest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
import CAWSCrypto
|
||||
|
||||
public extension Insecure {
|
||||
struct SHA1Digest : ByteDigest {
|
||||
public static var byteCount: Int { return Int(SHA_DIGEST_LENGTH) }
|
||||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
struct SHA1: _OpenSSLHashFunction {
|
||||
public typealias Digest = SHA1Digest
|
||||
public static var algorithm: OpaquePointer { return EVP_sha1() }
|
||||
var context: OpaquePointer
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// SHA2.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
#if canImport(CommonCrypto)
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import CommonCrypto
|
||||
|
||||
|
@ -101,41 +101,4 @@ public struct SHA512: CCHashFunction {
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
import CAWSCrypto
|
||||
|
||||
public struct SHA256Digest : ByteDigest {
|
||||
public static var byteCount: Int { return Int(SHA256_DIGEST_LENGTH) }
|
||||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
public struct SHA256: _OpenSSLHashFunction {
|
||||
public typealias Digest = SHA256Digest
|
||||
public static var algorithm: OpaquePointer { return EVP_sha256() }
|
||||
var context: OpaquePointer
|
||||
}
|
||||
|
||||
public struct SHA384Digest : ByteDigest {
|
||||
public static var byteCount: Int { return Int(SHA384_DIGEST_LENGTH) }
|
||||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
public struct SHA384: _OpenSSLHashFunction {
|
||||
public typealias Digest = SHA384Digest
|
||||
public static var algorithm: OpaquePointer { return EVP_sha384() }
|
||||
var context: OpaquePointer
|
||||
}
|
||||
|
||||
public struct SHA512Digest : ByteDigest {
|
||||
public static var byteCount: Int { return Int(SHA512_DIGEST_LENGTH) }
|
||||
public var bytes: [UInt8]
|
||||
}
|
||||
|
||||
public struct SHA512: _OpenSSLHashFunction {
|
||||
public typealias Digest = SHA512Digest
|
||||
public static var algorithm: OpaquePointer { return EVP_sha512() }
|
||||
var context: OpaquePointer
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// SymmetricKey.swift
|
||||
// based on the Vapor/open-crypto project which tries to replicate the CryptoKit framework interface
|
||||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
|
||||
#if !os(Linux)
|
||||
|
||||
import protocol Foundation.ContiguousBytes
|
||||
|
||||
/// Symmetric key object
|
||||
|
@ -15,10 +17,6 @@ public struct SymmetricKey: ContiguousBytes {
|
|||
let bytes = data.withUnsafeBytes { buffer in
|
||||
return [UInt8](buffer)
|
||||
}
|
||||
self.init(bytes: bytes)
|
||||
}
|
||||
|
||||
public init(bytes: [UInt8]) {
|
||||
self.bytes = bytes
|
||||
}
|
||||
|
||||
|
@ -26,3 +24,5 @@ public struct SymmetricKey: ContiguousBytes {
|
|||
return try self.bytes.withUnsafeBytes(body)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// Replicating the CryptoKit framework interface for < macOS 10.15
|
||||
// written by AdamFowler 2020/01/30
|
||||
|
||||
#if os(Linux)
|
||||
@_exported import Crypto
|
||||
#endif
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Created by Adam Fowler on 29/08/2019.
|
||||
//
|
||||
import Foundation
|
||||
import class Foundation.ProcessInfo
|
||||
|
||||
/// Protocol for providing credential details for accessing AWS services
|
||||
public protocol Credential {
|
||||
|
|
|
@ -7,7 +7,13 @@
|
|||
// AWS documentation about signing requests is here https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import struct Foundation.CharacterSet
|
||||
import struct Foundation.Data
|
||||
import struct Foundation.Date
|
||||
import class Foundation.DateFormatter
|
||||
import struct Foundation.Locale
|
||||
import struct Foundation.TimeZone
|
||||
import struct Foundation.URL
|
||||
import AWSCrypto
|
||||
import NIO
|
||||
import NIOHTTP1
|
||||
|
@ -21,7 +27,9 @@ public struct AWSSigner {
|
|||
/// AWS region you are working in
|
||||
public let region: String
|
||||
|
||||
static let hashedEmptyBody = SHA256.hash(data: [UInt8]()).description
|
||||
static let hashedEmptyBody = SHA256.hash(data: [UInt8]()).hexDigest()
|
||||
|
||||
static private let timeStampDateFormatter: DateFormatter = createTimeStampDateFormatter()
|
||||
|
||||
/// Initialise the Signer class with AWS credentials
|
||||
public init(credentials: Credential, name: String, region: String) {
|
||||
|
@ -69,8 +77,7 @@ public struct AWSSigner {
|
|||
public func signURL(url: URL, method: HTTPMethod = .GET, body: BodyData? = nil, date: Date = Date(), expires: Int = 86400) -> URL {
|
||||
let headers = HTTPHeaders([("host", url.host ?? "")])
|
||||
// Create signing data
|
||||
let signingData = AWSSigner.SigningData(url: url, method: method, headers: headers, body: body, date: AWSSigner.timestamp(date), signer: self)
|
||||
|
||||
var signingData = AWSSigner.SigningData(url: url, method: method, headers: headers, body: body, date: AWSSigner.timestamp(date), signer: self)
|
||||
// Construct query string. Start with original query strings and append all the signing info.
|
||||
var query = url.query ?? ""
|
||||
if query.count > 0 {
|
||||
|
@ -101,7 +108,7 @@ public struct AWSSigner {
|
|||
}
|
||||
|
||||
/// structure used to store data used throughout the signing process
|
||||
class SigningData {
|
||||
struct SigningData {
|
||||
let url : URL
|
||||
let method : HTTPMethod
|
||||
let hashedPayload : String
|
||||
|
@ -150,7 +157,7 @@ public struct AWSSigner {
|
|||
let kService = HMAC<SHA256>.authenticationCode(for: Data(name.utf8), using: SymmetricKey(data: kRegion))
|
||||
let kSigning = HMAC<SHA256>.authenticationCode(for: Data("aws4_request".utf8), using: SymmetricKey(data: kService))
|
||||
let kSignature = HMAC<SHA256>.authenticationCode(for: stringToSign(signingData: signingData), using: SymmetricKey(data: kSigning))
|
||||
return kSignature.description
|
||||
return kSignature.hexDigest()
|
||||
}
|
||||
|
||||
/// Stage 2 Create the string to sign as in https://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
|
||||
|
@ -158,7 +165,7 @@ public struct AWSSigner {
|
|||
let stringToSign = "AWS4-HMAC-SHA256\n" +
|
||||
"\(signingData.datetime)\n" +
|
||||
"\(signingData.date)/\(region)/\(name)/aws4_request\n" +
|
||||
SHA256.hash(data: canonicalRequest(signingData: signingData)).description
|
||||
SHA256.hash(data: canonicalRequest(signingData: signingData)).hexDigest()
|
||||
return Data(stringToSign.utf8)
|
||||
}
|
||||
|
||||
|
@ -182,13 +189,13 @@ public struct AWSSigner {
|
|||
let hash : String?
|
||||
switch payload {
|
||||
case .string(let string):
|
||||
hash = SHA256.hash(data: Data(string.utf8)).description
|
||||
hash = SHA256.hash(data: Data(string.utf8)).hexDigest()
|
||||
case .data(let data):
|
||||
hash = SHA256.hash(data: data).description
|
||||
hash = SHA256.hash(data: data).hexDigest()
|
||||
case .byteBuffer(let byteBuffer):
|
||||
let byteBufferView = byteBuffer.readableBytesView
|
||||
hash = byteBufferView.withContiguousStorageIfAvailable { bytes in
|
||||
return SHA256.hash(data: bytes).description
|
||||
return SHA256.hash(data: bytes).hexDigest()
|
||||
}
|
||||
}
|
||||
if let hash = hash {
|
||||
|
@ -202,14 +209,18 @@ public struct AWSSigner {
|
|||
static func hexEncoded(_ buffer: [UInt8]) -> String {
|
||||
return buffer.map{String(format: "%02x", $0)}.joined(separator: "")
|
||||
}
|
||||
|
||||
/// return a timestamp formatted for signing requests
|
||||
static func timestamp(_ date: Date) -> String {
|
||||
/// create timestamp dateformatter
|
||||
static private func createTimeStampDateFormatter() -> DateFormatter {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyyMMdd'T'HHmmss'Z'"
|
||||
formatter.timeZone = TimeZone(abbreviation: "UTC")
|
||||
formatter.locale = Locale(identifier: "en_US_POSIX")
|
||||
return formatter.string(from: date)
|
||||
return formatter
|
||||
}
|
||||
|
||||
/// return a timestamp formatted for signing requests
|
||||
static func timestamp(_ date: Date) -> String {
|
||||
return timeStampDateFormatter.string(from: date)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,3 +241,10 @@ extension String {
|
|||
static let uriAllowedCharacters = CharacterSet(charactersIn:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
|
||||
static let queryAllowedCharacters = CharacterSet(charactersIn:"/;+").inverted
|
||||
}
|
||||
|
||||
public extension Sequence where Element == UInt8 {
|
||||
/// return a hexEncoded string buffer from an array of bytes
|
||||
func hexDigest() -> String {
|
||||
return self.map{String(format: "%02x", $0)}.joined(separator: "")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// c_awscrypto.h
|
||||
// AWSSDKSwiftCore
|
||||
//
|
||||
// Created by Adam Fowler on 2019/08/08.
|
||||
//
|
||||
|
||||
#ifndef C_AWSSDK_OPENSSL_H
|
||||
#define C_AWSSDK_OPENSSL_H
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
HMAC_CTX *AWSCRYPTO_HMAC_CTX_new();
|
||||
void AWSCRYPTO_HMAC_CTX_free(HMAC_CTX* ctx);
|
||||
|
||||
EVP_MD_CTX *AWSCRYPTO_EVP_MD_CTX_new(void);
|
||||
void AWSCRYPTO_EVP_MD_CTX_free(EVP_MD_CTX *ctx);
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
#endif // C_AWSSDK_OPENSSL_H
|
|
@ -1,56 +0,0 @@
|
|||
//
|
||||
// shims.c
|
||||
// AWSSDKSwiftCore
|
||||
//
|
||||
// Created by Adam Fowler on 2019/08/08.
|
||||
//
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
// These are functions that shim over differences in different OpenSSL versions,
|
||||
// which are best handled by using the C preprocessor.
|
||||
#include "c_awscrypto.h"
|
||||
#include <string.h>
|
||||
|
||||
HMAC_CTX *AWSCRYPTO_HMAC_CTX_new() {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
|
||||
if (ctx != NULL) {
|
||||
HMAC_CTX_init(ctx);
|
||||
}
|
||||
return ctx;
|
||||
#else
|
||||
return HMAC_CTX_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AWSCRYPTO_HMAC_CTX_free(HMAC_CTX* ctx) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
if (ctx != NULL) {
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
#else
|
||||
HMAC_CTX_free(ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
EVP_MD_CTX *AWSCRYPTO_EVP_MD_CTX_new(void) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
return EVP_MD_CTX_create();
|
||||
#else
|
||||
return EVP_MD_CTX_new();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AWSCRYPTO_EVP_MD_CTX_free(EVP_MD_CTX *ctx) {
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
if (ctx != NULL) {
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
}
|
||||
#else
|
||||
EVP_MD_CTX_free(ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // __linux__
|
|
@ -1,93 +0,0 @@
|
|||
import XCTest
|
||||
@testable import AWSCrypto
|
||||
|
||||
final class AWSCryptoTests: XCTestCase {
|
||||
|
||||
// create a buffer of random values. Will always create the same given you supply the same z and w values
|
||||
// Random number generator from https://www.codeproject.com/Articles/25172/Simple-Random-Number-Generation
|
||||
func createRandomBuffer(_ w: UInt, _ z: UInt, size: Int) -> [UInt8] {
|
||||
var z = z
|
||||
var w = w
|
||||
func getUInt8() -> UInt8
|
||||
{
|
||||
z = 36969 * (z & 65535) + (z >> 16);
|
||||
w = 18000 * (w & 65535) + (w >> 16);
|
||||
return UInt8(((z << 16) + w) & 0xff);
|
||||
}
|
||||
var data = Array<UInt8>(repeating: 0, count: size)
|
||||
for i in 0..<size {
|
||||
data[i] = getUInt8()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func testMD5() {
|
||||
let data = createRandomBuffer(34, 2345, size: 234896)
|
||||
let digest = Insecure.MD5.hash(data: data)
|
||||
XCTAssertEqual(digest.description, "3abdd8d79be09bc250d60ada1f000912")
|
||||
}
|
||||
|
||||
func testSHA1() {
|
||||
let data = createRandomBuffer(41, 83, size: 562384)
|
||||
let digest = Insecure.SHA1.hash(data: data)
|
||||
XCTAssertEqual(digest.description, "2ea7cc3ce53e940a5877cbf5c8dfc992e4833fb3")
|
||||
}
|
||||
|
||||
func testSHA256() {
|
||||
let data = createRandomBuffer(872, 12489, size: 562741)
|
||||
let digest = SHA256.hash(data: data)
|
||||
XCTAssertEqual(digest.description, "3cff070559024d8652d1257e5f455787e95ebd8e95378d62df1a466f78860f74")
|
||||
}
|
||||
|
||||
func testSHA384() {
|
||||
let data = createRandomBuffer(872, 12489, size: 562741)
|
||||
let digest = SHA384.hash(data: data)
|
||||
XCTAssertEqual(digest.description, "d03a6a749dd66fb7bb261e34014c69e217684440b0c853727ac5bc12147edddc304cadbec8df8f77ec2ee44cc6b53bc3")
|
||||
}
|
||||
|
||||
func testSHA512() {
|
||||
let data = createRandomBuffer(872, 12489, size: 562741)
|
||||
let digest = SHA512.hash(data: data)
|
||||
XCTAssertEqual(digest.description, "15fc2df3a1c3649b83baf0f28d1a611bee8339a050d9d2c2ac4afad18f3187f725530b09bb6b2044131648d11d608c394804bc02ce2110b76d231ea75201000d")
|
||||
}
|
||||
|
||||
func testSHA256InitUpdateFinal() {
|
||||
let data = createRandomBuffer(8372, 12489, size: 562741)
|
||||
let digest = SHA256.hash(data: data)
|
||||
|
||||
var sha256 = SHA256()
|
||||
sha256.update(data: data[0..<238768])
|
||||
sha256.update(data: data[238768..<562741])
|
||||
let digest2 = sha256.finalize()
|
||||
|
||||
XCTAssertEqual(digest, digest2)
|
||||
XCTAssertEqual(digest.description, digest2.description)
|
||||
}
|
||||
|
||||
func testHMAC() {
|
||||
let data = createRandomBuffer(1, 91, size: 347237)
|
||||
let key = createRandomBuffer(102, 3, size: 32)
|
||||
let authenticationKey = HMAC<SHA256>.authenticationCode(for: data, using: SymmetricKey(bytes: key))
|
||||
XCTAssertEqual(authenticationKey.description, "ddec250211f1b546254bab3fb027af1acc4842898e8af6eeadcdbf8e2c6c1ff5")
|
||||
}
|
||||
|
||||
func testHMACInitUpdateFinal() {
|
||||
let data = createRandomBuffer(21, 81, size: 762061)
|
||||
let key = createRandomBuffer(102, 3, size: 32)
|
||||
let authenticationKey = HMAC<SHA256>.authenticationCode(for: data, using: SymmetricKey(bytes: key))
|
||||
|
||||
var hmac = HMAC<SHA256>(key: SymmetricKey(bytes: key))
|
||||
hmac.update(data: data[0..<126749])
|
||||
hmac.update(data: data[126749..<762061])
|
||||
let authenticationKey2 = hmac.finalize()
|
||||
|
||||
XCTAssertEqual(authenticationKey, authenticationKey2)
|
||||
XCTAssertEqual(authenticationKey.description, authenticationKey2.description)
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testMD5", testMD5),
|
||||
("testSHA256", testSHA256),
|
||||
("testHMAC", testHMAC),
|
||||
]
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
import XCTest
|
||||
|
||||
@testable import AWSSignerTests
|
||||
@testable import AWSCryptoTests
|
||||
|
||||
XCTMain([
|
||||
testCase(AWSSignerTests.allTests),
|
||||
testCase(AWSCryptoTests.allTests)
|
||||
testCase(AWSSignerTests.allTests)
|
||||
])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
FROM swift:5.1.3 as builder
|
||||
FROM swift:5.2 as builder
|
||||
|
||||
RUN apt-get -qq update && apt-get install -y \
|
||||
libssl-dev zlib1g-dev \
|
||||
zlib1g-dev \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
|
Loading…
Reference in New Issue