Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4: Linux sign/verify #10

Merged
merged 4 commits into from
Dec 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 93 additions & 8 deletions Sources/CryptorRSA/CryptorRSA.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

import Foundation

#if os(Linux)
import OpenSSL
#endif

// MARK: -

// MARK: -
Expand Down Expand Up @@ -313,13 +317,55 @@ public class CryptorRSA {
}

#if os(Linux)

throw Error(code: ERR_NOT_IMPLEMENTED, reason: "Not implemented yet.")


// EVP_MD_CTX_create() renamed to _new
let md_ctx = EVP_MD_CTX_create()
defer {
EVP_MD_CTX_destroy(md_ctx)
}

let (md, _) = algorithm.algorithmForSignature // (md, padding)
// TODO. Add the padding option. Right now we are ignoring it

// convert RSA key to EVP
let evp_key = EVP_PKEY_new()
var rc = EVP_PKEY_set1_RSA(evp_key, key.reference)
guard rc == 1 else {
let source = "Couldn't create key reference from key data"
if let reason = CryptorRSA.getLastError(source: source) {

throw Error(code: ERR_ADD_KEY, reason: reason)
}
throw Error(code: ERR_ADD_KEY, reason: source + ": No OpenSSL error reported.")
}

// Determine the size of the signature
var sig_len: Int = Int(EVP_PKEY_size(evp_key))
let sig = UnsafeMutablePointer<UInt8>.allocate(capacity: sig_len)

EVP_DigestSignInit(md_ctx, nil, md, nil, evp_key)

// convert Data to UnsafeRawPointer!
_ = self.data.withUnsafeBytes({ (message: UnsafePointer<UInt8>) -> Int32 in
return EVP_DigestUpdate(md_ctx, message, self.data.count)
})

rc = EVP_DigestSignFinal(md_ctx, sig, &sig_len)
guard rc == 1 else {
let source = "Couldn't create key reference from key data"
if let reason = CryptorRSA.getLastError(source: source) {

throw Error(code: ERR_SIGNING_FAILED, reason: reason)
}
throw Error(code: ERR_SIGNING_FAILED, reason: source + ": No OpenSSL error reported.")
}

return SignedData(with: Data(bytes: sig, count: sig_len))

#else

var response: Unmanaged<CFError>? = nil
let sData = SecKeyCreateSignature(key.reference, algorithm.alogrithmForSignature, self.data as CFData, &response)
let sData = SecKeyCreateSignature(key.reference, algorithm.algorithmForSignature, self.data as CFData, &response)
if response != nil {

guard let error = response?.takeRetainedValue() else {
Expand Down Expand Up @@ -366,20 +412,59 @@ public class CryptorRSA {

#if os(Linux)

throw Error(code: ERR_NOT_IMPLEMENTED, reason: "Not implemented yet.")
let md_ctx = EVP_MD_CTX_create()
defer {
EVP_MD_CTX_destroy(md_ctx)
}

let (md, _) = algorithm.algorithmForSignature // (md, padding)
// TODO. Add the padding option. Right now we are ignoring it

// convert RSA key to EVP
let evp_key = EVP_PKEY_new()
var rc = EVP_PKEY_set1_RSA(evp_key, key.reference)
guard rc == 1 else {
let source = "Couldn't create key reference from key data"
if let reason = CryptorRSA.getLastError(source: source) {

throw Error(code: ERR_ADD_KEY, reason: reason)
}
throw Error(code: ERR_ADD_KEY, reason: source + ": No OpenSSL error reported.")
}

EVP_DigestVerifyInit(md_ctx, nil, md, nil, evp_key)

rc = self.data.withUnsafeBytes({ (message: UnsafePointer<UInt8>) -> Int32 in
return EVP_DigestUpdate(md_ctx, message, self.data.count)
})
guard rc == 1 else {
let source = "Couldn't create key reference from key data"
if let reason = CryptorRSA.getLastError(source: source) {

throw Error(code: ERR_VERIFICATION_FAILED, reason: reason)
}
throw Error(code: ERR_VERIFICATION_FAILED, reason: source + ": No OpenSSL error reported.")
}

// Unlike other return values above, this return indicates if signature verifies or not
rc = signature.data.withUnsafeBytes({ (sig: UnsafePointer<UInt8>) -> Int32 in
return EVP_DigestVerifyFinal(md_ctx, sig, signature.data.count)
})

return (rc == 1) ? true : false

#else

var response: Unmanaged<CFError>? = nil
let result = SecKeyVerifySignature(key.reference, algorithm.alogrithmForSignature, self.data as CFData, signature.data as CFData, &response)
let result = SecKeyVerifySignature(key.reference, algorithm.algorithmForSignature, self.data as CFData, signature.data as CFData, &response)
if response != nil {

guard let error = response?.takeRetainedValue() else {

throw Error(code: CryptorRSA.ERR_SIGNING_FAILED, reason: "Verification failed. Unable to determine error.")
throw Error(code: CryptorRSA.ERR_VERIFICATION_FAILED, reason: "Verification failed. Unable to determine error.")
}

throw Error(code: CryptorRSA.ERR_SIGNING_FAILED, reason: "Verification failed with error: \(error)")
throw Error(code: CryptorRSA.ERR_VERIFICATION_FAILED, reason: "Verification failed with error: \(error)")
}

return result
Expand Down
27 changes: 25 additions & 2 deletions Sources/CryptorRSA/CryptorRSADigest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,33 @@ public extension Data {
#endif
}

#if !os(Linux)
#if os(Linux)
public var algorithmForSignature: (UnsafePointer<EVP_MD>, Int32) {

switch self {

case .sha1:
return (EVP_sha1(), RSA_PKCS1_PADDING)

case .sha224:
return (EVP_sha224(), RSA_PKCS1_PADDING)

case .sha256:
return (EVP_sha256(), RSA_PKCS1_PADDING)

case .sha384:
return (EVP_sha384(), RSA_PKCS1_PADDING)

case .sha512:
return (EVP_sha512(), RSA_PKCS1_PADDING)

}
}

#else

@available(macOS 10.12, iOS 10.0, *)
public var alogrithmForSignature: SecKeyAlgorithm {
public var algorithmForSignature: SecKeyAlgorithm {

switch self {

Expand Down
4 changes: 2 additions & 2 deletions Tests/CryptorRSATests/CryptorRSATests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ class CryptorRSATests: XCTestCase {
// ("test_simpleEncryption", test_simpleEncryption),
// ("test_longStringEncryption", test_longStringEncryption),
// ("test_randomByteEncryption", test_randomByteEncryption),
// ("test_signVerifyAllDigestTypes", test_signVerifyAllDigestTypes),
// ("test_signVerifyBase64", test_signVerifyBase64),
("test_signVerifyAllDigestTypes", test_signVerifyAllDigestTypes),
("test_signVerifyBase64", test_signVerifyBase64),
]
}
}
Expand Down