Skip to content
This repository has been archived by the owner on Sep 3, 2020. It is now read-only.

Commit

Permalink
clean up usafeBytes
Browse files Browse the repository at this point in the history
  • Loading branch information
FranzBusch committed May 28, 2018
1 parent 3685e40 commit 966fc22
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 35 deletions.
56 changes: 39 additions & 17 deletions Sources/Crypto/Cipher/Cipher.swift
@@ -1,5 +1,6 @@
import CNIOOpenSSL
import Foundation
import Bits

// MARK: Ciphers

Expand Down Expand Up @@ -122,20 +123,22 @@ public final class Cipher {
let key = key.convertToData()
let iv = iv?.convertToData()

guard EVP_CipherInit_ex(ctx, algorithm.c, nil, key.withUnsafeBytes { $0 }, iv?.withUnsafeBytes { $0 }, mode.rawValue) == 1 else {
throw CryptoError.openssl(identifier: "EVP_CipherInit_ex", reason: "Failed initializing cipher context.")
}

let keyLength = EVP_CIPHER_CTX_key_length(ctx)
let keyLength = EVP_CIPHER_key_length(algorithm.c)
guard keyLength == key.count else {
throw CryptoError(identifier: "cipherKeySize", reason: "Invalid cipher key length \(key.count) != \(keyLength).")
}

let ivLength = EVP_CIPHER_iv_length(algorithm.c)
guard (ivLength == 0 && (iv == nil || iv?.count == 0)) || (iv != nil && iv?.count == Int(ivLength)) else {
throw CryptoError(identifier: "cipherIVSize", reason: "Invalid cipher IV length \(iv?.count ?? 0) != \(ivLength).")
}

if let _iv = iv {
let ivLength = EVP_CIPHER_CTX_iv_length(ctx)
guard ivLength == _iv.count else {
throw CryptoError(identifier: "cipherIVSize", reason: "Invalid cipher IV length \(_iv.count) != \(ivLength).")
guard key.withByteBuffer({ keyBuffer in
iv.withByteBuffer { ivBuffer in
EVP_CipherInit_ex(ctx, algorithm.c, nil, keyBuffer.baseAddress!, ivBuffer?.baseAddress, mode.rawValue)
}
}) == 1 else {
throw CryptoError.openssl(identifier: "EVP_CipherInit_ex", reason: "Failed initializing cipher context.")
}
}

Expand All @@ -157,14 +160,17 @@ public final class Cipher {
/// - throws: `CryptoError` if update fails or data conversion fails.
public func update(data: LosslessDataConvertible, into buffer: inout Data) throws {
let input = data.convertToData()
let inputLength: Int32 = numericCast(input.count)

var chunk = Data(repeating: 0, count: numericCast(inputLength + algorithm.blockSize - 1))
var chunk = Data(count: input.count + Int(algorithm.blockSize) - 1)
var chunkLength: Int32 = 0
guard EVP_CipherUpdate(ctx, chunk.withUnsafeMutableBytes { $0 }, &chunkLength, input.withUnsafeBytes { $0 }, inputLength) == 1 else {

guard chunk.withMutableByteBuffer({ chunkBuffer in
input.withByteBuffer { inputBuffer in
EVP_CipherUpdate(ctx, chunkBuffer.baseAddress!, &chunkLength, inputBuffer.baseAddress!, Int32(truncatingIfNeeded: inputBuffer.count))
}
}) == 1 else {
throw CryptoError.openssl(identifier: "EVP_CipherUpdate", reason: "Failed updating cipher.")
}
buffer += chunk.subdata(in: 0..<numericCast(chunkLength))
buffer += chunk.prefix(upTo: Int(chunkLength))
}

/// Finalizes the encryption or decryption, appending any additional data into the supplied buffer.
Expand All @@ -184,12 +190,13 @@ public final class Cipher {
/// - buffer: Mutable buffer to append any remaining encrypted or decrypted data to.
/// - throws: `CryptoError` if finalization fails.
public func finish(into buffer: inout Data) throws {
var chunk = Data(repeating: 0, count: numericCast(algorithm.blockSize))
var chunk = Data(count: Int(algorithm.blockSize))
var chunkLength: Int32 = 0
guard EVP_CipherFinal_ex(ctx, chunk.withUnsafeMutableBytes { $0 }, &chunkLength) == 1 else {

guard chunk.withMutableByteBuffer({ EVP_CipherFinal_ex(ctx, $0.baseAddress!, &chunkLength) }) == 1 else {
throw CryptoError.openssl(identifier: "EVP_CipherFinal_ex", reason: "Failed finishing cipher.")
}
buffer += chunk.subdata(in: 0..<numericCast(chunkLength))
buffer += chunk.prefix(upTo: Int(chunkLength))
}

/// Cleans up and frees the allocated OpenSSL cipher context.
Expand All @@ -210,3 +217,18 @@ public enum CipherMode: Int32 {
/// Decrypts encrypted ciphertext back to its original value.
case decrypt = 0
}

/// Wrapper to allow for safely working with a potentially-nil Data's byte buffer.
extension Optional where Wrapped == Data {
public func withByteBuffer<T>(_ closure: (BytesBufferPointer?) throws -> T) rethrows -> T {
switch self {
case .some(let data):
return try data.withByteBuffer({ try closure($0) })
case .none:
return try closure(nil)
}
}

// Note: It's iffy to try this with a mutable buffer, so an Optional version
// of withMutableByteBuffer is not provided.
}
10 changes: 6 additions & 4 deletions Sources/Crypto/Digest/Digest.swift
Expand Up @@ -117,7 +117,8 @@ public final class Digest {
/// - throws: `CryptoError` if update fails or data conversion fails.
public func update(data: LosslessDataConvertible) throws {
let data = data.convertToData()
guard EVP_DigestUpdate(ctx, .init(data.withUnsafeBytes { $0 }), data.count) == 1 else {

guard data.withByteBuffer({ EVP_DigestUpdate(ctx, $0.baseAddress!, $0.count) }) == 1 else {
throw CryptoError.openssl(identifier: "EVP_DigestUpdate", reason: "Failed updating digest.")
}
}
Expand All @@ -134,12 +135,13 @@ public final class Digest {
/// - returns: Digest data
/// - throws: `CryptoError` if the finalization step fails.
public func finish() throws -> Data {
var hash = Data(repeating: 0, count: Int(EVP_MAX_MD_SIZE))
var hash = Data(count: Int(EVP_MAX_MD_SIZE))
var count: UInt32 = 0
guard EVP_DigestFinal_ex(ctx, hash.withUnsafeMutableBytes { $0 }, &count) == 1 else {

guard hash.withMutableByteBuffer({ EVP_DigestFinal_ex(ctx, $0.baseAddress!, &count) }) == 1 else {
throw CryptoError.openssl(identifier: "EVP_DigestFinal_ex", reason: "Failed finalizing digest.")
}
return Data(hash[0..<Int(count)])
return hash.prefix(upTo: Int(count))
}

deinit { EVP_MD_CTX_destroy(ctx) }
Expand Down
13 changes: 8 additions & 5 deletions Sources/Crypto/MAC/HMAC.swift
Expand Up @@ -103,7 +103,8 @@ public final class HMAC {
/// - throws: `CryptoError` if the initialization / reset fails or data conversion fails.
public func reset(key: LosslessDataConvertible) throws {
let key = key.convertToData()
guard HMAC_Init_ex(&ctx, .init(key.withUnsafeBytes { $0 }), Int32(key.count), algorithm.c, nil) == 1 else {

guard key.withByteBuffer({ HMAC_Init_ex(&ctx, $0.baseAddress!, Int32($0.count), algorithm.c, nil) }) == 1 else {
throw CryptoError.openssl(identifier: "HMAC_Init_ex", reason: "Failed initializing HMAC context.")
}
}
Expand All @@ -123,7 +124,8 @@ public final class HMAC {
/// - throws: `CryptoError` if the update fails or data conversion fails.
public func update(data: LosslessDataConvertible) throws {
let data = data.convertToData()
guard HMAC_Update(&ctx, .init(data.withUnsafeBytes { $0 }), data.count) == 1 else {

guard data.withByteBuffer({ HMAC_Update(&ctx, $0.baseAddress!, $0.count) }) == 1 else {
throw CryptoError.openssl(identifier: "HMAC_Update", reason: "Failed updating HMAC digest.")
}
}
Expand All @@ -141,12 +143,13 @@ public final class HMAC {
/// - returns: Digest data
/// - throws: `CryptoError` if the finalization step fails.
public func finish() throws -> Data {
var hash = Data(repeating: 0, count: Int(EVP_MAX_MD_SIZE))
var hash = Data(count: Int(EVP_MAX_MD_SIZE))
var count: UInt32 = 0
guard HMAC_Final(&ctx, hash.withUnsafeMutableBytes { $0 }, &count) == 1 else {

guard hash.withMutableByteBuffer({ HMAC_Final(&ctx, $0.baseAddress!, &count) }) == 1 else {
throw CryptoError.openssl(identifier: "HMAC_Final", reason: "Failed finalizing HMAC digest.")
}
return Data(hash[0..<Int(count)])
return hash.prefix(upTo: Int(count))
}

deinit { HMAC_CTX_cleanup(&ctx) }
Expand Down
10 changes: 1 addition & 9 deletions Sources/Random/RandomProtocol.swift
Expand Up @@ -7,16 +7,8 @@ public protocol DataGenerator {
}

extension Data {
/// Converts the data to an unsafe raw pointer.
internal var rawPointer: UnsafeRawPointer {
let bytes: UnsafePointer<UInt8> = withUnsafeBytes { $0 }
return UnsafeRawPointer(bytes)
}

internal func cast<T>(to: T.Type = T.self) -> T {
return rawPointer
.assumingMemoryBound(to: T.self)
.pointee
return withUnsafeBytes { (p: UnsafePointer<T>) in p.pointee }
}
}

Expand Down

0 comments on commit 966fc22

Please sign in to comment.