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
Related
I'm working on a project that'll open PDF books inside application. I'm fetching the books from the server and they're coming as locked pdf pages and I'm also fetching each pages' password with another API.
The problem is, the list of passwords are coming as AES encrypted. I can not decrypt them properly. I don't know what am I missing. My code is below. Waiting for your answers. Thank you :) (I'm using CrytoSwift library)
(I'm taking key and iv with an another function and keeping them in two different variables.)
import CryptoSwift
var myEncryptedData : String = ""
var key32 : String = ""
var iv16: String = ""
func decryptData() {
do {
let aes = try AES(key: Array(key32.utf8), blockMode: CBC(iv: Array(iv16.utf8)), padding: .pkcs7)
let ciphertext = try aes.decrypt(myEncryptedData.bytes)
print(String(data: Data(ciphertext), encoding: .utf8));
} catch {
print(error)
}
}
I tried to decrypt encryptedString with AES decryption by using CryptoSwift library but I couldn't fetch the data that I expected.
I just added this code just below "do" and it worked
let d = Data(base64Encoded: encryptedString)
Working version is:
do {
let d = Data(base64Encoded: encryptedString)
let aes = try AES(key: Array(key32.utf8), blockMode: CBC(iv: Array(iv16.utf8)), padding: .pkcs7)
let ciphertext = try aes.decrypt(d!.bytes)
let stringCipherText = String(data: Data(ciphertext), encoding: .utf8)
} catch {
print(error)
}
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
}
}
IN swift I am trying to encrypt text same as CryptoJS encryption. But both are not same here I share with you URL, I need to do the same encryption in Swift. Please help me, here I attach my code also.
Demo CryptoJS encryption
in this URL we are using CryptoJS encryption with ECB and pkcs7. Same code I am doing in ios but not the same
import UIKit
import Foundation
import CryptoSwift
class CryptoViewController: UIViewController {
let KEY = "0123456789123456"
override func viewDidLoad() {
super.viewDidLoad()
self.aesCBC_Encrypt(AES_KEY: KEY, payload: "Hello World!")
}
func aesCBC_Encrypt(AES_KEY: String,payload: String) -> String {
var result = ""
do {
let key: [UInt8] = Array(AES_KEY.utf8) as [UInt8]
let iv = AES.randomIV(AES.blockSize)
let bytes = payload.bytes
let aes = try! AES(key: key, blockMode: ECB(), padding: .pkcs7)
//let encrypted = try aes.encrypt(Array(self.utf8))
let encrypted = try aes.encrypt(bytes)
print("encrypted: \(encrypted)")
result = encrypted.toHexString()
print("AES Encryption Result: \(result)")
} catch {
print("Error: \(error)")
}
return result
}
}
From my code, I am getting this Result
AES Encryption Result: 1b8019c2add38f33de9099aefd5369f5
But when I am try to Encryption from CryptoJS, Then I am getting this Result
Encrypted Text:
Aeoo7GP6b4l/Pdxz2RS+qA==
i am trying to encrypt and decrypt a string using RSAUtils swift library, i am having a problem returning the decrypted text to it's original value . this is the code:
let PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJh+/sdLdlVVcM5V5/j/RbwM8SL++Sc3dMqMK1nP73XYKhvO63bxPkWwaY0kwcUU40+QducwjueVOzcPFvHf+fECAwEAAQ=="
let sampleText:String = "WHATS UP"
let encrypted:Data? = RSAUtils.encryptWithRSAPublicKey(sampleText.data(using: String.Encoding.utf8)!, pubkeyBase64: PUBLIC_KEY, keychainTag: "12345")!
let decrypted:Data? = RSAUtils.decryptWithRSAPublicKey(encrypted!, pubkeyBase64: PUBLIC_KEY, keychainTag: "12345")
let encryptedDataText = encrypted!.base64EncodedString(options: NSData.Base64EncodingOptions())
let decryptedDataText = decrypted!.base64EncodedString(options: NSData.Base64EncodingOptions())
I tried to convert the decrypted data to string using this code:
if let string = String(data: decrypted! , encoding: .utf16) {
print(string)
} else {
print("not a valid UTF-16 sequence")
}
But it prints "㺸ꉄ꤈꽹㲞㏯荘뼵鉉큅령嬰ꢤẲ毪쌶⏤ᱼ埡佒�ࡊᩏ⧚㨈؍੯屍" I also tried to decode the base64 value using :
let decodedData = Data(base64Encoded: decryptedDataText)!
let decodedString = String(data: decodedData, encoding: .utf8)!
print(decodedString)
It causes an error
Fatal error: Unexpectedly found nil while unwrapping an O
probably the text is not a valid base64 string.
How can i convert the decrypted data to it's original value.
Thanks.
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()