Skip to content

Commit

Permalink
Bind Sha1, crc32 and crc32c (#209)
Browse files Browse the repository at this point in the history
  • Loading branch information
waahm7 authored Nov 7, 2023
1 parent fd1756b commit 2b5fc3b
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 34 deletions.
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,15 +248,15 @@ packageTargets.append(contentsOf: [
cSettings: cSettings
),
.target(
name: "AwsChecksums",
name: "AwsCChecksums",
dependencies: ["AwsCCommon"],
path: "aws-common-runtime/aws-checksums",
exclude: awsCChecksumsExcludes,
cSettings: cSettings
),
.target(
name: "AwsCEventStream",
dependencies: ["AwsChecksums", "AwsCCommon", "AwsCIo", "AwsCCal"],
dependencies: ["AwsCChecksums", "AwsCCommon", "AwsCIo", "AwsCCal"],
path: "aws-common-runtime/aws-c-event-stream",
exclude: awsCEventStreamExcludes,
cSettings: cSettings
Expand All @@ -269,7 +269,7 @@ packageTargets.append(contentsOf: [
"AwsCCompression",
"AwsCIo",
"AwsCCommon",
"AwsChecksums",
"AwsCChecksums",
"AwsCEventStream",
.product(name: "Collections", package: "swift-collections")],
path: "Source/AwsCommonRuntimeKit"
Expand Down
29 changes: 29 additions & 0 deletions Source/AwsCommonRuntimeKit/crt/Checksums.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0.

import struct Foundation.Data
import AwsCChecksums

extension Data {

/// Computes the CRC32 over data.
/// - Parameter previousCrc32: Pass 0 in the previousCrc32 parameter as an initial value unless continuing to update a running crc in a subsequent call.
public func crc32(previousCrc32: UInt32 = 0) -> UInt32 {
self.withUnsafeBytes { bufferPointer in
return aws_checksums_crc32(bufferPointer.baseAddress?.assumingMemoryBound(to: UInt8.self),
Int32(count),
previousCrc32)
}
}

/// Computes the crc32c over data.
/// - Parameter previousCrc32c: Pass 0 in the previousCrc32c parameter as an initial value unless continuing to update a running crc in a subsequent call.
public func crc32c(previousCrc32c: UInt32 = 0) -> UInt32 {
self.withUnsafeBytes { bufferPointer in
return aws_checksums_crc32c(bufferPointer.baseAddress?.assumingMemoryBound(to: UInt8.self),
Int32(count),
previousCrc32c)
}
}

}
65 changes: 65 additions & 0 deletions Source/AwsCommonRuntimeKit/crt/Hash.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0.
import struct Foundation.Date
import struct Foundation.Data
import struct Foundation.TimeInterval
import AwsCCal

extension String {

/// Computes the md5 hash over input and writes the digest output to 'output'. Use this if you don't need to stream the data you're hashing and you can load
/// the entire input to hash into memory.
/// - Parameter truncate: If you specify truncate something other than 0, the output will be truncated to that number of bytes.
public func base64EncodedMD5(truncate: Int = 0) throws -> String {
let bufferSize = 16
var bufferData = Data(count: bufferSize)
try bufferData.withUnsafeMutableBytes { bufferPointer in
var buffer = aws_byte_buf_from_empty_array(bufferPointer.baseAddress, bufferSize)
guard self.withByteCursorPointer({ strCursorPointer in
aws_md5_compute(allocator.rawValue, strCursorPointer, &buffer, truncate)
}) == AWS_OP_SUCCESS else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
}
return bufferData.base64EncodedString()
}
}

extension Data {

/// Computes the sha256 hash over data.
/// - Parameter truncate: If you specify truncate something other than 0, the output will be truncated to that number of bytes. For
/// example, if you want a SHA256 digest as the first 16 bytes, set truncate to 16.
public func sha256(truncate: Int = 0) throws -> Data {
try self.withUnsafeBytes { bufferPointer in
var byteCursor = aws_byte_cursor_from_array(bufferPointer.baseAddress, count)
let bufferSize = Int(AWS_SHA256_LEN)
var bufferData = Data(count: bufferSize)
try bufferData.withUnsafeMutableBytes { bufferDataPointer in
var buffer = aws_byte_buf_from_empty_array(bufferDataPointer.baseAddress, bufferSize)
guard aws_sha256_compute(allocator.rawValue, &byteCursor, &buffer, truncate) == AWS_OP_SUCCESS else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
}
return bufferData
}
}

/// Computes the sha1 hash over data.
/// - Parameter truncate: If you specify truncate something other than 0, the output will be truncated to that number of bytes. For
/// example, if you want a SHA1 digest as the first 10 bytes, set truncate to 10.
public func sha1(truncate: Int = 0) throws -> Data {
try self.withUnsafeBytes { bufferPointer in
var byteCursor = aws_byte_cursor_from_array(bufferPointer.baseAddress, count)
let bufferSize = Int(AWS_SHA1_LEN)
var bufferData = Data(count: bufferSize)
try bufferData.withUnsafeMutableBytes { bufferDataPointer in
var buffer = aws_byte_buf_from_empty_array(bufferDataPointer.baseAddress, bufferSize)
guard aws_sha1_compute(allocator.rawValue, &byteCursor, &buffer, truncate) == AWS_OP_SUCCESS else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
}
return bufferData
}
}
}
30 changes: 0 additions & 30 deletions Source/AwsCommonRuntimeKit/crt/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,6 @@ class Box<T> {

extension String {

public func base64EncodedMD5(truncate: Int = 0) throws -> String {
let bufferSize = 16
var bufferData = Data(count: bufferSize)
try bufferData.withUnsafeMutableBytes { bufferPointer in
var buffer = aws_byte_buf_from_empty_array(bufferPointer.baseAddress, bufferSize)
guard self.withByteCursorPointer({ strCursorPointer in
aws_md5_compute(allocator.rawValue, strCursorPointer, &buffer, truncate)
}) == AWS_OP_SUCCESS else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
}
return bufferData.base64EncodedString()
}

func withByteCursor<Result>(_ body: (aws_byte_cursor) -> Result
) -> Result {
return self.withCString { arg1C in
Expand All @@ -62,22 +48,6 @@ extension String {

extension Data {

/// Computes the sha256 hash over data.
public func sha256(truncate: Int = 0) throws -> Data {
try self.withUnsafeBytes { bufferPointer in
var byteCursor = aws_byte_cursor_from_array(bufferPointer.baseAddress, count)
let bufferSize = Int(AWS_SHA256_LEN)
var bufferData = Data(count: bufferSize)
try bufferData.withUnsafeMutableBytes { bufferDataPointer in
var buffer = aws_byte_buf_from_empty_array(bufferDataPointer.baseAddress, bufferSize)
guard aws_sha256_compute(allocator.rawValue, &byteCursor, &buffer, truncate) == AWS_OP_SUCCESS else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
}
return bufferData
}
}

func withAWSByteBufPointer<Result>(_ body: (UnsafeMutablePointer<aws_byte_buf>) -> Result) -> Result {
let count = self.count
return self.withUnsafeBytes { rawBufferPointer -> Result in
Expand Down
21 changes: 21 additions & 0 deletions Test/AwsCommonRuntimeKitTests/crt/ChecksumsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0.
import XCTest
import AwsCCommon
@testable import AwsCommonRuntimeKit

class ChecksumsTests: XCBaseTestCase {

func testCRC32() throws {
XCTAssertEqual("".data(using: .utf8)!.crc32(), 0)
XCTAssertEqual("Hello".data(using: .utf8)!.crc32(), 4157704578)
XCTAssertEqual("{\"foo\":\"base64 encoded sha1 checksum\"}".data(using: .utf8)!.crc32(), 1195144130)
}

func testCRC32C() throws {
XCTAssertEqual("".data(using: .utf8)!.crc32c(), 0)
XCTAssertEqual("Hello".data(using: .utf8)!.crc32c(), 2178485787)
XCTAssertEqual("{\"foo\":\"base64 encoded sha1 checksum\"}".data(using: .utf8)!.crc32c(), 3565301023)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import XCTest
import AwsCCommon
@testable import AwsCommonRuntimeKit

class UtilityTests: XCBaseTestCase {
class HashTests: XCBaseTestCase {

func testMd5() throws {
let hello = "Hello"
Expand Down Expand Up @@ -41,6 +41,26 @@ class UtilityTests: XCBaseTestCase {
XCTAssertEqual(sha256Data.base64EncodedString(), "lBSnDP4sj/yN8eIVOJlv+vC56hw+7JtN0132GiMQXRg=")
}


func testSha1() throws {
let hello = "Hello".data(using: .utf8)!
XCTAssertEqual(try! hello.sha1().encodeToHexString(), "f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0")
}

func testSha1EmptyString() throws {
let empty = "".data(using: .utf8)!
XCTAssertEqual(try! empty.sha1().encodeToHexString(), "da39a3ee5e6b4b0d3255bfef95601890afd80709")
}

func testSha1PayloadOutOfScope() throws {
var sha1Data: Data! = nil
do {
let payload = "{\"foo\":\"base64 encoded sha1 checksum\"}".data(using: .utf8)!
sha1Data = try! payload.sha1()
}
XCTAssertEqual(sha1Data.encodeToHexString(), "bc3c579755c719da780d4429d6e9cf32f0c29c7e")
}

func testByteCursorListToStringArray() throws {
let list: UnsafeMutablePointer<aws_array_list> = allocator.allocate(capacity: 1)
defer {
Expand Down

0 comments on commit 2b5fc3b

Please sign in to comment.