Swift Sha512 Encryption ( translate Kotlin code ) - swift

This is the Kotlin code:
private fun verify(inputDataToVerify: String, signature: String): Boolean {
return try {
val pubKey = "XXXMYPUBKEYXXX"
val bytesFromPropFile = pubKey.toByteArray()
val keySpec = X509EncodedKeySpec(Base64.decode(bytesFromPropFile, Base64.DEFAULT))
val keyFactory = KeyFactory.getInstance("RSA")
val publicKey = keyFactory.generatePublic(keySpec)
Signature.getInstance("SHA512WithRSA").run {
initVerify(publicKey)
update(inputDataToVerify.toByteArray())
verify(Base64.decode(signature.toByteArray(), Base64.DEFAULT))
}
} catch (ex: Exception) {
Timber.e(ex)
false
}
}
I have to convert this piece of code to Swift because I need the same behavior in my iOS app but I'm really new to encryption.
How can I do? I need third part library?

You don't need to encrypt anything, you need to verify a signature. The algorithms are:
SubjectPublicKeyInfo or spki for the public key (as defined in the X509 certificate standards, hence the name);
The old RSA / PKCS#1 signature verification algorithm (obviously with SHA-512 as hash algorithm).
Note that toByteArray() encodes a string to binary using UTF-8 as default. Obviously it should not really be needed before base 64 decoding, but yeah...

i found a solution with SwiftyRSA, that's the method
private func verifySignature(inputDataToVerify: String, signature: String) -> Bool{
let pubKeyString = environmentService.getNexiPubKey()
do {
let publicKey = try PublicKey(pemEncoded: pubKeyString)
let clear = try ClearMessage(string: inputDataToVerify, using: .utf8)
let sign = try Signature(base64Encoded: signature)
let isSuccessfull = try clear.verify(with: publicKey, signature: sign, digestType: .sha512)
return isSuccessfull
}
catch let error{
print(error)
return false
}
}

Related

P384 Public Key getting "IncorrectParameterSize"

I am working on the ECDSA Algorithm where i am taking signature from the APIs and i have one local public key inside constant file.
Below is my code when i am trying to run this and verify the signature then i am getting error in this link
let publicKey = try P384.Signing.PublicKey.init(derRepresentation: privateKeyPemBytes)
I am receiving "incorrectParameterSize" this error from the catch block. Can anyone having idea about this Encryption algorithm and help me out?
func verifySignature(signedData: Data, signature: Data, publicKey: String) -> Bool {
var result = false
do {
if #available(iOS 14.0, *) {
let decodedData = Data(base64Encoded: publicKey)
let publicKeyPemBytes = [UInt8](decodedData!)
let publicKey = try P384.Signing.PublicKey.init(derRepresentation: privateKeyPemBytes)
let hash = SHA256.hash(data: signedData)
let signing384 = try P384.Signing.ECDSASignature(derRepresentation: signature)
if publicKey.isValidSignature(signing384, for: hash) {
result = true
}
} else {
// Fallback on earlier versions
}
} catch {
print("\(error)")
}
return result
}
In the discussion it turned out that the public key has the X.509/SPKI format, is ASN.1/DER encoded and is available as Base64 encoded string.
However, it is a P-256 key and not a P-384 key, which is the cause of the error. The fix is to use P256 in the code instead of P384.
The signature is in ASN.1/DER format, as Base64 encoded string.
Swift supports both the ASN.1/DER signature format and the P1363 signature format for ECDSA signatures (s. here for the difference).
The following code shows the verification for both signature formats using sample data:
import Foundation
import Crypto
// message to be signed
let msg = "The quick brown fox jumps over the lazy dog".data(using: .utf8)!
let hash = SHA256.hash(data: msg)
// public key import
let publicKeyX509DerB64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMpHT+HNKM7zjhx0jZDHyzQlkbLV0xk0H/TFo6gfT23ish58blPNhYrFI51Q/czvkAwCtLZz/6s1n/M8aA9L1Vg=="
let publicKeyX509Der = Data(base64Encoded: publicKeyX509DerB64)
let publicKey = try! P256.Signing.PublicKey.init(derRepresentation: publicKeyX509Der!)
// verifying an ASN.1/DER encoded signature
let signatureDerB64 = "MEYCIQCDMThF51R3S3CfvtVQomSO+kotOMH6HfvVcx04a21QwQIhAP2Patj0N3CVoeB6yiZt/gEVh9qQ7mtyvF4FiWBYtE0a"
let signatureDer = Data(base64Encoded: signatureDerB64)
let signature1 = try! P256.Signing.ECDSASignature(derRepresentation: signatureDer!)
print(publicKey.isValidSignature(signature1, for: hash)) // true
// verifying a P1363 encoded signature
let signatureP1363B64 = "gzE4RedUd0twn77VUKJkjvpKLTjB+h371XMdOGttUMH9j2rY9DdwlaHgesombf4BFYfakO5rcrxeBYlgWLRNGg=="
let signatureP1363 = Data(base64Encoded: signatureP1363B64)
let signature2 = try! P256.Signing.ECDSASignature(rawRepresentation: signatureP1363!)
print(publicKey.isValidSignature(signature2, for: hash)) // true

Kraken EAPI: Invalid key

I am trying to do a client with swift however I cannot communicate with the private api {"error": ["EAPI: Invalid key"]}
I use CCHmac function and tried to have a look at different api implementation.
I just can't get whats wrong...
Here is my code:
func getTradeBalance(basedAsset: String, completionBlock: #escaping BlockResult) {
guard let url = URL(string: "\(krakenUtils.rootUrl)/\(krakenUtils.version)/private/Balance") else {
return
}
let nonce: String = String(Int(Date().timeIntervalSince1970.rounded()))
let path = "/\(krakenUtils.version)/private/Balance"
let pubKey = krakenUtils.publicKey
let params = ["nonce": nonce]
//Sign = HMAC-SHA512 of URI + SHA256-POSTDATAS + base64decodedSecret
let sign = getMessageSignature(path: path,
nonce: nonce)
Alamofire.request(url, method: .post,
parameters: params, encoding: JSONEncoding.default,
headers: ["API-Key": pubKey,
"API-Sign": sign])
.responseJSON { resp in
let result = self.handleResponse(result: resp)
guard let json = result.0 else {
completionBlock(nil, result.1)
return
}
print(json)
}
}
private func getMessageSignature(path: String, nonce: String) -> String {
let secretDecoded = Data(base64Encoded: krakenUtils.privateKey, options: Data.Base64DecodingOptions.init(rawValue: 0))!
let np = (nonce + "nonce=" + nonce).sha256().data(using: .utf8, allowLossyConversion: false)!
var pathNP = path.data(using: .utf8, allowLossyConversion: false)!
pathNP.append(contentsOf: np)
let lRet = HMAC.sign(data: pathNP, algorithm: .sha512, key: secretDecoded).base64EncodedString()
return lRet
}
public static func sign(data: Data, algorithm: Algorithm, key: Data) -> Data {
let signature = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: algorithm.digestLength)
data.withUnsafeBytes { dataBytes in
key.withUnsafeBytes { keyBytes in
CCHmac(algorithm.algorithm, keyBytes, key.count, dataBytes, data.count, signature)
}
}
return Data(bytes: signature, count: algorithm.digestLength)
}
This is guide for authenticated call HTTPS Header:
API-Key = API key
API-Sign = Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key
This is guide for authenticated call POST Data:
nonce = always increasing unsigned 64 bit integer
otp = two-factor password (if two-factor enabled, otherwise not required)
For the API-Key you use krakenUtils.publicKey. The name suggests you use some public key (do not know where you got it)
However this should be your personal API-Key. You can get it at the kraken site (login with your account) and create an API key. You also get your API-code here. They go together as a pair
Although this is an old question, many users (including myself) who have attempted to use Kraken’s API have encountered and reported similar problems (INVALID KEY). Recently I reported the issue I was having to a Kraken rep…after an exchange with several reps it was discovered that there was a flaw in the posted Kraken example on their website. Here is some of the exchange:
...”In the method QueryPrivateEndpoint there is a line of code (should be line 256 from the file downloaded) that looks like this:
String apiEndpointFullURL = baseDomain + privatePath + endPointName + "?" + inputParameters;
It needs to be modified to look like this:
String apiEndpointFullURL = baseDomain + privatePath + endPointName;
After you make that code change, the Invalid Key error should go away.
…….
Thank you for your gratitude and pointing out the mistake to our attention.
We are pleased to know the issue has been resolved.
“……
They will post the update to their example code on their website.
Also, it’s worth noting that an improper/inconsistent ORDER of the parameters in a call that has parameters associated with it can cause an INVALID KEY error.

HMAC-SHA1 for OAuth Signature in Swift

I'm trying to make OAuth module for Swift 2 in my application. I'm stucked with HMAC-SHA1 signature generating because my function returns incorrect base64 hmac-sha1 for signature. Can you help me with it? What's wrong?
func URLEncodedKey() -> String? {
let key = "efgh"
let string = "GET&http%3A%2F%2Fhost.net%2Fresource&name%3Dvalue%26name%3Dvalue%26oauth_consumer_key%3Dabcd%26oauth_nonce%3DxUwWEy3LVsI%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1441375089%26oauth_token%3Dijkl%26oauth_version%3D1.0"
guard let keyData = key.dataUsingEncoding(NSUTF8StringEncoding),
stringData = string.dataUsingEncoding(NSUTF8StringEncoding),
outputData = NSMutableData(length: Int(CC_SHA1_DIGEST_LENGTH)) else {
return nil
}
outputData.length = Int(CC_SHA1_DIGEST_LENGTH)
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA1),
keyData.bytes, keyData.length,
stringData.bytes, stringData.length,
outputData.mutableBytes)
return outputData
.base64EncodedStringWithOptions([])
}
For checking:
String for encode: in code
Correct: O8UjUTYX1UxKF93KaY/mta9HETs=
My (incorrect): f5elSONqP6nPdpgBIyroJTCN19s=
Correct encoder is here (javascript): https://oauth.googlecode.com/svn/code/javascript/example/signature.html
Your method must returns correct result as is.
See http://oauth.net/core/1.0/#signing_process:
The HMAC-SHA1 signature method uses the HMAC-SHA1 signature algorithm as defined in [RFC2104] where the Signature Base String is the text and the key is the concatenated values (each first encoded per Parameter Encoding) of the Consumer Secret and Token Secret, separated by an ‘&’ character (ASCII code 38) even if empty.
The key should be "efgh&mnop" in this case.

How do I encode an unmanaged<SecKey> to base64 to send to another server?

I'm trying to use key pair encryption to validate identity between my app and my PHP server. To do this I need to send the public key over to the server after I generate it in my app.
if let pubKey = NSData(base64EncodedData: publicKey, options: NSDataBase64DecodingOptions.allZeros)! {
println(pubKey)
}
publicKey is of type Unmanaged<SecKey>.
The error I'm getting in the above code is: Extra argument 'base64EncodedData' in call
How would I do this? Is there a better way?
Edit: This is how the keypair is generated:
var publicKeyPtr, privateKeyPtr: Unmanaged<SecKey>?
let parameters = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): 2048
]
let result = SecKeyGeneratePair(parameters, &publicKeyPtr, &privateKeyPtr)
let publicKey = publicKeyPtr!.takeRetainedValue()
let privateKey = privateKeyPtr!.takeRetainedValue()
let blockSize = SecKeyGetBlockSize(publicKey)
Edit 2: So the issue is that SecKey is not NSData, so my question here should be: How do I convert a publicKey:SecKey to NSData?
It seems that you can temporary store the key to keychain and then get it back and convert it to data:
func convertSecKeyToBase64(inputKey: SecKey) ->String? {
// First Temp add to keychain
let tempTag = "de.a-bundle-id.temp"
let addParameters :[String:AnyObject] = [
String(kSecClass): kSecClassKey,
String(kSecAttrApplicationTag): tempTag,
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecValueRef): inputKey,
String(kSecReturnData):kCFBooleanTrue
]
var keyPtr: Unmanaged<AnyObject>?
let result = SecItemAdd(addParameters, &keyPtr)
switch result {
case noErr:
let data = keyPtr!.takeRetainedValue() as! NSData
// Remove from Keychain again:
SecItemDelete(addParameters)
let encodingParameter = NSDataBase64EncodingOptions(rawValue: 0)
return data.base64EncodedStringWithOptions(encodingParameter)
case errSecDuplicateItem:
println("Duplicate Item")
SecItemDelete(addParameters)
return nil
case errSecItemNotFound:
println("Not found!")
return nil
default:
println("Error: \(result)")
return nil
}
}
While the fact is barely documented, you can pull out everything you need (that is, modulus and exponent) from the SecKey using SecKeyCopyAttributes.
See here for the details.
Swift 4 method to get base64 string from SecKey, publicKey :)
guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey!, nil) else {
NSLog("\tError obtaining export of public key.")
return ""
}
let publicKeyNSData = NSData(data: publicKeyData as Data)
let publicKeyBase64Str = publicKeyNSData.base64EncodedString()

Encrypted NSData to NSString in obj-c?

I have an iPhone app which encrypts an inputted NSString using CCCrypt (AES256) and a plaintext key. The string and key are given to the encryption method which returns an NSData object.
Requesting [data description] where 'data' is the encrypted string data gives an NSString like: "<0b368353 a707e7de 3eee5992 ee69827e e3603dc2 b0dbbc0b 861ca87d f39ce72a>" but when I try to convert that to an NSString, I get "(null)".
I need to return an NSString to the user, which can be used to decrypt back to the original string using the same plaintext key. If the 'description' property of the NSData object can return a string, is there any way I can produce an NSString from the NSData object without getting "(null)"?
UPDATE: Thanks to Quinn, who suggests using Base64 encoding to produce the muddled string. From what I understand, Base64 encoding does not simply swap characters, but the character exchange depends on the position, so that's fine.
My only concern is that I want to be able to encrypt the message with a 'passphrase', and require the identical passphrase to be entered when the muddled string needs to be decoded - can anybody suggest ways to implement this?
First off, DO NOT use -[NSData description] to create an NSString for such purposes. (It's best to treat -description as debugging output. I apologize if my previous answer misled you, I was merely printing the description to demonstrate that the NSData can be encrypted and decrypted.) Instead, use NSString's -dataUsingEncoding: and -initWithData:encoding: methods to convert between NSData and NSString. Even with these, note that AES-encrypted data will probably not translate well into strings as-is — some byte sequences just won't play nicely, so it's a good idea to encode the data before creating the string.
I'd suggest you try Base64 encoding the NSData, since Base64 data can always be represented as an ASCII string. (Of course, when you do that, you'll have to decode from Base64 before decrypting.)
Here are some helpful resources...
Colloquy has some code that does encoding/decoding on NSData (header and implementation)
Google Toolbox for Mac has similar functionality (header and implementation)
A Cocoa With Love blog post on the topic.
A CocoaDev.com wiki page on the topic.
Edit: I was assuming you'd combine this with my answer to your previous question on AES encryption of NSString objects. Encoding data as Base64 doesn't place any restrictions on the data itself — it can certainly be AES-enrypted data itself. Here's what to do if you just want string input and output:
Encryption
Provide the NSString to be encrypted, and the passphrase to use for encrypting.
Convert the string to an NSData and perform AES encryption on it (see previous question).
Base64-encode the NSData, then create and return and NSString of the encoded output.
Decryption
Provide the encrypted and encoded string, and the passphrase to use for decrypting.
Create an NSData from the first string, then Base64-decode the data.
Perform AES decryption on the data, then create and return an NSString.
It's really just a matter of chaining the two parts together and performing them in reverse on the way out. From my previous answer, you can modify encryptString:withKey: to perform the last step and return a string, and change decryptData:withKey: to be decryptString:withKey: and accept two strings. It's pretty straightforward.
I have put together a complete bundle of categories for NSData and NSString to provide AES256 encryption for strings.
Please see my answer on the 'original' question for more details.
I have similar requirement where I need to encrypt all the strings when user enters the password to enter to app so that those sensitive strings doesn't remain unencrypted all the time. So I have to keep those strings encrypted and decrypt as an when require only.
It was a simple requirement and I wanted to keep it light. So I have created a small Obfuscator using lot of useful info shared by #RobNapier in one his blog. It might help for those who are looking a lightweight solution with lot of juicy comments.
import Foundation
import CommonCrypto
// A thin wrapper around interfacing
public enum CrypticAlgo {
case AlgoAES
case AlgoDES
func blockSize() -> Int {
switch self {
case .AlgoAES:
return kCCBlockSizeAES128
case .AlgoDES:
return kCCBlockSizeDES
}
}
func keySize() -> size_t {
switch self {
case .AlgoAES:
return kCCKeySizeAES128
case .AlgoDES:
return kCCKeySizeDES
}
}
func algo() -> UInt32 {
switch self {
case .AlgoAES:
return CCAlgorithm(kCCAlgorithmAES)
case .AlgoDES:
return CCAlgorithm(kCCAlgorithmDES)
}
}
}
public final class MGObfuscate {
private var ivData: [UInt8]?
private var derivedKey: Data?
private let crypticAlgo: CrypticAlgo
public init(password: String, salt: String, algo: CrypticAlgo) {
//Quickly get the data to release the password string
let passwordData = password.data(using: .utf8)!
//
// Rounds require for 1 sec delay in generating hash.
// Salt is a public attribute. If attacker somehow get the drivedKey and try to crack
// the password via brute force, The delay due to Rounds will make it frustrating
// to get actual password and deter his/her efforts.
//
let rounds = CCCalibratePBKDF(CCPBKDFAlgorithm(kCCPBKDF2), password.count,
salt.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), Int(CC_SHA256_DIGEST_LENGTH), 1000)
let saltData = salt.data(using: .utf8)!
derivedKey = MGObfuscate.derivedKey(for: passwordData,
saltData: saltData, rounds: rounds)
self.crypticAlgo = algo
var ivData = [UInt8](repeating: 0, count: algo.blockSize())
// Random criptographically secure bytes for initialisation Vector
let rStatus = SecRandomCopyBytes(kSecRandomDefault, ivData.count, &ivData)
self.ivData = ivData
// print(ivData)
guard rStatus == errSecSuccess else {
fatalError("seed not generated \(rStatus)")
}
}
#inline(__always) private static func derivedKey(for passwordData: Data, saltData: Data, rounds: UInt32) -> Data {
var derivedData = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
let result = derivedData.withUnsafeMutableBytes { (drivedBytes: UnsafeMutablePointer<UInt8>?) in
passwordData.withUnsafeBytes({ (passwordBytes: UnsafePointer<Int8>!) in
saltData.withUnsafeBytes({ (saltBytes: UnsafePointer<UInt8>!) in
CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2), passwordBytes, passwordData.count, saltBytes, saltData.count, CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256), rounds, drivedBytes, Int(CC_SHA256_DIGEST_LENGTH))
})
})
}
if kCCSuccess != result {
fatalError("failed to generate hash for password")
}
return derivedData
}
private func runCryptic(operation: Int, inputData: Data, keyData: Data, ivData: Data) -> Data {
let cryptLength = size_t(inputData.count + crypticAlgo.blockSize())
var cryptData = Data(count: cryptLength)
let keyLength = crypticAlgo.keySize()
var bytesProcessed: size_t = 0
let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
inputData.withUnsafeBytes { dataBytes in
keyData.withUnsafeBytes { keyBytes in
ivData.withUnsafeBytes{ ivBytes in
CCCrypt(CCOperation(operation),
crypticAlgo.algo(),
CCOptions(kCCOptionPKCS7Padding),
keyBytes, keyLength,
ivBytes,
dataBytes, inputData.count,
cryptBytes, cryptLength,
&bytesProcessed)
}
}
}
}
if cryptStatus == CCCryptorStatus(kCCSuccess) {
cryptData.removeSubrange(bytesProcessed..<cryptData.count)
} else {
fatalError("Error: \(cryptStatus)")
}
return cryptData
}
public func encriptAndPurge(inputString: inout String?) -> Data? {
if let inputdata = inputString?.data(using: .utf8) {
inputString = nil
return runCryptic(operation: kCCEncrypt, inputData: inputdata, keyData: derivedKey!, ivData: Data(bytes: ivData!))
}
return nil
}
public func encript(inputString: String) -> Data {
let inputdata = inputString.data(using: .utf8)!
return runCryptic(operation: kCCEncrypt, inputData: inputdata, keyData: derivedKey!, ivData: Data(bytes: ivData!))
}
public func decript(data: Data, result: (String) -> Void) {
let data = runCryptic(operation: kCCDecrypt, inputData: data, keyData: derivedKey!, ivData: Data(bytes: ivData!))
result(String(data: data, encoding: .utf8)!)
}
public func purge() {
ivData = nil
derivedKey = nil
}
}