How to Generate RSA Public key using exponent and modulus in SWIFT? - swift

I am trying to encrypt the AES key with RSAEncryption, I have created a Function for both, AES Encryption will first encrypt the DATA and then call the RSAEncryption to encrypt the AES Encryption Key itself and then send it to the server for response.
Below is what i tried, right now i am just checking if the public key that i am creating on runtime to encrypt matches with the public key that it should be, when i run the program, i print the pem representation of public key corresponding to the modulus and exponent, the prefix of the RSA public key is missing 32 characters from it.
CODE:
import Foundation
import Alamofire
import SwiftyRSA
class Encryption {
private let rsaModulus: String = ""
private let rsaExponent: String = ""
public func rsaEncryption(password: String, data: Data, modulus: String, exponent: String) -> String? {
if let modData = Data(base64Encoded: modulus),
let expData = Data(base64Encoded: exponent),
let keyData = Rsa.generatePublicKey(withModulus: modData, exponent: expData) {
let keyDict:[NSObject:NSObject] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
kSecAttrKeySizeInBits: NSNumber(value: 2048),
kSecReturnPersistentRef: true as NSObject
]
let publicKey = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, nil)
let pub = try! PublicKey(reference: publicKey!)
let pem = try! pub.pemString()
let clear = try! ClearMessage(string: "Clear Text", using: .utf8)
let encrypted = try! clear.encrypted(with: pub, padding: .PKCS1)
print("Encrypted AES Key: \(encrypted.base64String)")
print(separator: "\n")
print(pem) //Print pem to check public key generated
}
return "NO"
}
}
Result Output :
Encrypted AES Key: /.../
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAvvJwQMvjUI7DDnC2PYwGNGJrkq6acdkjIW1+WznI68FyfVWb15Gz
hiJ7IVVbPo1Rphkbr0Gs8vrkunwBxVIb1wCjiiwqdoR7EUvUHrk5WkNcSoNEu2l0
VnRVuFe+XTKrnQsgfRy2TzyW3eG2kOkQBHWwJCQT6pFOwLXhY4JwSBzdhPIUk7HM
20ntqmamMnKMEmEC2N+qOfBx2hKVv2s7bwGBI8NZoIdt6dbhFXgv5NWN+U9Mx3kd
mXpjz7CaGgxfbBhTy6SfJQzN0Exfv4VGxOHRDkO0Mmu/d2VIeT4Q8lM53YZWuyCm
/pZ4XCgi9Z/2ZmQmCszSOc2/495JQcV9ZQIDAQAB
-----END RSA PUBLIC KEY-----
Actual Output of public key should be :
-----BEGIN PUBLIC KEY-----
**MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A**MIIBCgKCAQEAvvJwQMvjUI7DDnC2PYwG
NGJrkq6acdkjIW1+WznI68FyfVWb15GzhiJ7IVVbPo1Rphkbr0Gs8vrkunwBxVIb
1wCjiiwqdoR7EUvUHrk5WkNcSoNEu2l0VnRVuFe+XTKrnQsgfRy2TzyW3eG2kOkQ
BHWwJCQT6pFOwLXhY4JwSBzdhPIUk7HM20ntqmamMnKMEmEC2N+qOfBx2hKVv2s7
bwGBI8NZoIdt6dbhFXgv5NWN+U9Mx3kdmXpjz7CaGgxfbBhTy6SfJQzN0Exfv4VG
xOHRDkO0Mmu/d2VIeT4Q8lM53YZWuyCm/pZ4XCgi9Z/2ZmQmCszSOc2/495JQcV9
ZQIDAQAB
-----END PUBLIC KEY-----
Characters between stars are missing from the result output.

Related

How to create SecKey from pem file in Swift

I'm trying to create a SecKey using SecKeyCreateWithData. I'm loading the private key from a .pem file, and I create the key pair like this.
openssl genrsa -des3 -out WM_IO_my_rsa_key_pair 2048
Here is the code, but I get a SecKeyCreate init(RSAPublicKey) failed: -50 error.
import UIKit
import Security
func createKey(pem: String) -> SecKey? {
let attributes: [NSObject : NSObject] = [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
kSecAttrKeySizeInBits: NSNumber(value: 2048)
]
let privateKey = pem
.replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "")
.replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "")
.split(separator: "\n").joined()
guard let privateKeyData = Data(base64Encoded: privateKey, options: .ignoreUnknownCharacters) else {
return nil
}
var error: Unmanaged<CFError>?
return SecKeyCreateWithData(privateKeyData as CFData, attributes as CFDictionary, &error)
}
let privateKey = """
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCpySPOXAAsi1jN
vxDrNfinFOUZlLk38P8BF2ukJWU7OOAXol6TG8fFrn8O+UVW4jjPTZjLT9G6385N
iervmwopS5CtHS2p0ptLm1ExigZAuS/LTaIkw3yugr4b+5roEwL9nFW0Qfd4o/ds
3lKPtdwtO0rfqTfuZ6CqcQP0sTJcky7nk3mIyz6jZOZE2QLL/oF/oUKsi5Wt5uJp
uluZ+gt087Ftm1oGKR8lZt5bucbD7WZnmlckNyUh7O973mqqDZ6zTwrgNuxIBmtr
afNetsgZv6/We56IWenKayWW1xA9icPhmViJtzPU3Gu8HW/FMovyRZAMFD1Yzf+L
eiSGC5x9AgMBAAECggEAGOrN+HEEDYV9yOQrhXlsPokQfkqXTCBwLCbVw0dBrglQ
yecoXgqLrPVI7Fek13VnxPSsYdoa+4Pw8Ow2sGdefGT8nItVskCYTeZDajPJayJC
Y2HHVAHkgG/rmou4VirEG5gf885ilS/rFe0izLhx0amL+XsKHFDVAW6ImBaRP4iU
82fkZtLlh4DLi6w/oNu3ePZkMeTl4aAkJH8gRy2Mzsyl0DNi5+mH0du12BVSca58
iAXEhufIweTvDqb3lx0CR5+0+dbk/MeIvoklDCkPAlK9IOXr9m0UYjWXNYTADLi8
PmQf8k7pf74ma/2bFuT8LakIA6z3HEwLO7iKm4VVOQKBgQDYVG7AJWJL3DDMCpz3
csP+fKccr72Q3VKCZ5uq0jC/Wp4jfNip/b76Rt3xb8nqzgIDntu+B6Vzz6HPB5d4
j8510lNZrRzIQj0unxOx7pJHIGHhGv2dJ00IqVa5aNL8aCNhxXhgR3vIojyoo8R9
nc4WAQu4ID+xOCsqtvNBm6T1jwKBgQDI67Obqjqt1IDWV5/7dJundWEtfGBdHYBd
iuVxoyqOKAeasaWXuUxJgpzy/ukIAuI5WtzR8nP/US8MIUkRj7eXDi3E2tgpkUwZ
IT9StEdXM8UznpyXfQX9oMmlHC8MZRwLJkldcbGMjsfXsVcAMbe+HBmXs+izsxqe
icsEPPe/MwKBgQDU2O5HPAElJrcUa3TZux/AayF5hih8OmcOS6bMQhcYj658uD/t
se6QDd4dyaHf12X/7fPDW36dHjPUoWGVi9jV8GV2HG/vUc0k6/vS3CsstF3ZwFa8
o4iV9xePQeYl1sjJUCQKhwrx8z6/prKT7gpxeAHx3jkMw3klg/CAIwYBXQKBgFIc
OT+Rlv95S9nM352k7wPFrZwoKz2Ck/YmkFQbiYWlCE6I8RKLcIjOLxQDZvqWKxuj
bYEDY7Jg3ChJ5hGeOTorWjsL8LE0JvRSKQ3EjS8vAhVxaa9jMbKQJjgqx3N6Uraf
w/XDQ/scUsFsQRDcQKoZ07+yj5P4yxUlXOlzfRAPAoGBALri0o6PhjRRPwKzE3gO
ClUJ1KTEhA55GOPs5ZDPxDckYigSC+R8nLLxeueFiFkIDrar85tiO9J4P0j7tovB
Ivu6+QWQso3U3RC2Deb3uWagKHOt9m+DB8LdKsLpY/aPUXzPKKXJ4BWVIYExm418
FUzB7PCpc0Cdjg6A7Ca2cP0U
-----END PRIVATE KEY-----
"""
createKey(pem: privateKey)
The pem key is base64 encoded, so you need to decode it first:
guard let privateKeyData = Data(base64Encoded: privateKey, options: .ignoreUnknownCharacters) else {
...

How do I parse an x509 certificate and extract its key's signature in Swift?

I'm trying to generate an RSA pair key, then add an X.509 certificate to the header of Public Key. For this, I'm using library SwiftyRSA
The problem is that when I add the X.509 certificate to the header I cannot parse the Public Key. When I print the Public Key after that, it still shows the same as it was without the certificate.
But when I print bytes it shows different bytes, without the certificate it shows 270 bytes, with the certificate it shows 294bytes. This means it's adding the certificate but it's not parsing it with the certificate.
After reading deeper in SwiftyRSA library, it says:
Warning : Storing (with SwiftyRSA's methods) or creating a PublicKey
instance will automatically strip the header from the key. For more
info, see Under the hood above.
If worth mentioning even the case that is still Opened there.
I'm still looking for a solution but cannot find any. The code that I tried to implement:
if let password = passwordTextField.text {
//Generate RSA
guard let keyPair = try? SwiftyRSA.generateRSAKeyPair(sizeInBits: 2048),
let privateKeyPem = try? keyPair.privateKey.pemString(),
let publicKeyPem = try? keyPair.publicKey.pemString()
else {
return
}
/// Generate Certificate in format X.509 from Public Key
let publicKey = try! PublicKey(data: keyPair.publicKey.data())
let publicKeyData = try! keyPair.publicKey.data()
let publicKey_with_X509_header = try! SwiftyRSA.prependX509KeyHeader(keyData: publicKeyData)
let publicKey509 = try! PublicKey(data: publicKey_with_X509_header)
print(try! publicKey.pemString()) // Without Certificate
print(try! publicKey509.pemString()) // With Certificate
// These two print results are completely the same, but it should be different.
// Encrypt private key
let salt = String.random(length: 32)
let aesKey = Array(String((password + salt).prefix(32)).utf8)
let iv = [UInt8](String(salt.prefix(16)).utf8)
guard let aes = try? AES(key: aesKey, blockMode: CBC(iv: iv), padding: .pkcs7),
let inputData = privateKeyPem.data(using: .utf8),
let encryptedBytes = try? aes.encrypt(inputData.bytes)
else {
return
}
let encryptedData = NSData(bytes: encryptedBytes, length: encryptedBytes.count)
let base64String = encryptedData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
// Print keys and salt
print(try! publicKey509.pemString())
print(base64String)
print(salt)
}
How can I parse the Public Key with an x509 certificate?
I would appreciate any contribution.
As mentioned above, you won't be able to create x509 certificate with SwiftyRSA. You can actually do this with Security framework.
First, you need to create an extension of Data, which will be used to add the certificate to the public key.
extension Data {
public func dataByPrependingX509Header() -> Data {
let result = NSMutableData()
let encodingLength: Int = (self.count + 1).encodedOctets().count
let OID: [CUnsignedChar] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00]
var builder: [CUnsignedChar] = []
// ASN.1 SEQUENCE
builder.append(0x30)
// Overall size, made of OID + bitstring encoding + actual key
let size = OID.count + 2 + encodingLength + self.count
let encodedSize = size.encodedOctets()
builder.append(contentsOf: encodedSize)
result.append(builder, length: builder.count)
result.append(OID, length: OID.count)
builder.removeAll(keepingCapacity: false)
builder.append(0x03)
builder.append(contentsOf: (self.count + 1).encodedOctets())
builder.append(0x00)
result.append(builder, length: builder.count)
// Actual key bytes
result.append(self)
return result as Data
}
}
Then, make sure you import Security and, you change your code to this:
// Generate keys
if let password = passwordTextField.text {
//Generate RSA
let attributes: [String: Any] = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): 4096, // you can change the size to 2048, but 4096 has higher security.
String(kSecPrivateKeyAttrs): [
String(kSecAttrIsPermanent): true,
String(kSecAttrApplicationTag): "com.example.keys.mykey"]
]
var error: Unmanaged<CFError>?
// Private Key
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
fatalError("Error: \(error.debugDescription)")
}
let privateKeyData = SecKeyCopyExternalRepresentation(privateKey, &error)
let privData = privateKeyData as Data?
let privateKeyString = privData!.base64EncodedString()
print("Private Key")
print(privateKeyString)
// You'll probably need to structure Private and public key to go in new line every time after 76 character
let structuredPrivateKeyString = privateKeyString.inserting(separator: "\n", every: 76)
let privateKeyFinal = "-----BEGIN RSA PRIVATE KEY-----\n" + structuredPrivateKeyString + "\n\n-----END RSA PRIVATE KEY-----"
print(privateKeyFinal)
// Public Key
let publicKey = SecKeyCopyPublicKey(privateKey) // generate public key from private key
let publicKeyData = SecKeyCopyExternalRepresentation(publicKey!, &error)
let pubData = publicKeyData as Data? // We need to turn it into data so we can add the certificate or print it as string
print("Public Key")
print(pubData!.base64EncodedString())
// Add x509 certificate to public key
let publicKeyX509 = SecKeyCopyPublicKey(privateKey)
let publicKeyDataX509 = SecKeyCopyExternalRepresentation(publicKeyX509!, &error)
let pubData1 = publicKeyDataX509 as Data?
let x509Data = pubData1!.dataByPrependingX509Header() // Here we add the certificate (Function that we created previosly in Data extension).
var publicKeyX509String = x509Data.base64EncodedString()
print("Public Key x509")
print(publicKeyX509String)
let structuredPublicKeyX509String = publicKeyX509String.inserting(separator: "\n", every: 76)
let publicKeyFinal = "-----BEGIN RSA PUBLIC KEY-----\n\(structuredPublicKeyX509String)\n\n-----END RSA PUBLIC KEY-----"
print("Public Key for the API")
print(publicKeyFinal)
// Encrypt private key
let salt = String.random(length: 32)
let aesKey = Array(String((password + salt).prefix(32)).utf8)
let iv = [UInt8](String(salt.prefix(16)).utf8)
guard let aes = try? AES(key: aesKey, blockMode: CBC(iv: iv), padding: .pkcs7),
let inputData = privateKeyFinal.data(using: .utf8),
let encryptedBytes = try? aes.encrypt(inputData.bytes)
else {
setLoadingView(visible: false)
return
}
let encryptedData = NSData(bytes: encryptedBytes, length: encryptedBytes.count)
let base64String = encryptedData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
// Print keys and salt
print(publicKeyFinal)
print(base64String)
print(salt)
}
Note: I added a comment on each line that I thought is important, so you will now what's happening.

How can I generate an ed25519 key pair in OpenSSH format with swift?

I tried to generate the keys with different approaches, get the raw data but I can't find any library that transform these bytes into OpenSSH compatible public and private keys.
Approach 1:
let privateKeyParams: [String: Any] = [
kSecAttrIsPermanent as String: false,
]
let parameters: [String: Any] = [
String(kSecClass): kSecClassKey,
String(kSecAttrKeyType): kSecAttrKeyTypeECSECPrimeRandom,
String(kSecAttrKeySizeInBits): 256,
kSecPrivateKeyAttrs as String: privateKeyParams
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(parameters as CFDictionary, &error) else {
throw error!.takeRetainedValue() as Error
}
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
throw KeyGeneratorError(description: "Failed to generate the public key")
}
guard let privateKeyData = SecKeyCopyExternalRepresentation(privateKey, nil) as? Data else {
throw KeyGeneratorError(description: "Failed to extract data from key")
}
guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) as? Data else {
throw KeyGeneratorError(description: "Failed to extract data from key")
}
Approach 2 (using CryptoKit):
let privateKey = Curve25519.KeyAgreement.PrivateKey()
let publicKey = privateKey.publicKey
let privateKeyData = privateKey.rawRepresentation
let publicKeyData = publicKey.rawRepresentation
Approach 3 (using SwCrypt library):
let (privateKey, publicKey) = try SwCrypt.CC.EC.generateKeyPair(256)
I always get an object of type "Data" but I cannot transform this data into an OpenSSH string of this type:
Private Key:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAZ9c1i+q
9gMY51eotxWjeRAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIPAWeGw39CgOruIW
i0N/yji4+K/r/VPdwgg6BQD3e1Y5AAAAoJ9WV+HMYQx4bPyjTprzDQfLmcl3BiCC6hSe93
c29g2jd8zMSr4fVH0ECby6iaLxlwYbvRz+gdIqpI8MpxEJ+XBzWYNWM8r9tD7wS4rHICXg
rjXnXfq6OUfiq+RzYFrn6mLYE3PwA//IsNyrnk9tHk9y4E0dj1JlYHQ4Y5LBOg3DsosTNo
qTVa9+7XrCuSxDMaXqVMgSMbBo0H8bolX/4uM=
-----END OPENSSH PRIVATE KEY-----
Public Key:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPAWeGw39CgOruIWi0N/yji4+K/r/VPdwgg6BQD3e1Y5

Swift RSA Encryption Public Key to Java Server is failing

I am trying to create public base64 key from RSA Private key using Security framework. Here is snippet.
let tag = "com.example.keys.mykey"
public extension SecKey {
static func generateBase64Encoded2048BitRSAKey() throws -> (private: String, public: String) {
let type = kSecAttrKeyTypeRSA
let attributes: [String: Any] =
[kSecAttrKeyType as String: type,
kSecAttrKeySizeInBits as String: 2048
]
var error: Unmanaged<CFError>?
guard let key = SecKeyCreateRandomKey(attributes as CFDictionary, &error),
let data = SecKeyCopyExternalRepresentation(key, &error) as Data?,
let publicKey = SecKeyCopyPublicKey(key),
let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
throw error!.takeRetainedValue() as Error
}
return (private: data.base64EncodedString(), public: publicKeyData.base64EncodedString())
}
}
do {
let (pvtKey, pubKey) = try SecKey.generateBase64Encoded2048BitRSAKey()
print(pubKey)
} catch let error {
print(error)
}
This is the output
MIIBCgKCAQEA1ZafTYboquQbCTZMEb1IqHKIr8wiDjdn6e0toRajZCQo9W5zuTlEuctrjJJQ08HcOuK3BPFRaFTUP1RBFvnba/T2S1Mc6WVX81b0DmKS8aPJ83TvvQlH3bZjVqFzndXJHJatcXRkZKlbidNQYxV9OYFCRLwgR5PBoJ1P5tp8f8735vIADOBL/93nFywODSjAWLXcyG5tUyRlRGX7eDodL7jqVOFxVMB7K9UOJehPuJQiheykyPSbBSLE6raZbpCHlranTLdihWYFs2tYbxzNrVbXzgKIxDDjrhDLVFvo3beudKQcLQkSO+m2LJIDT91zAnxVQ075AIn80ZHh5kdyQQIDAQAB
But this public key is not getting accepted by our Java server. It is throwing exception for the same.
Here is java snippet
public static void main(String[] args) {
String pubKey = "MIIBCgKCAQEA1ZafTYboquQbCTZMEb1IqHKIr8wiDjdn6e0toRajZCQo9W5zuTlEuctrjJJQ08HcOuK3BPFRaFTUP1RBFvnba/T2S1Mc6WVX81b0DmKS8aPJ83TvvQlH3bZjVqFzndXJHJatcXRkZKlbidNQYxV9OYFCRLwgR5PBoJ1P5tp8f8735vIADOBL/93nFywODSjAWLXcyG5tUyRlRGX7eDodL7jqVOFxVMB7K9UOJehPuJQiheykyPSbBSLE6raZbpCHlranTLdihWYFs2tYbxzNrVbXzgKIxDDjrhDLVFvo3beudKQcLQkSO+m2LJIDT91zAnxVQ075AIn80ZHh5kdyQQIDAQAB";
PublicKey key = getPublic(pubKey);
}
public static PublicKey getPublic(String key) {
PublicKey pbKey = null;
try {
byte[] keyBytes = Base64.getDecoder().decode(key);
System.out.println(keyBytes.length);
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
pbKey = factory.generatePublic(spec);
} catch (Exception e) {
e.printStackTrace();
}
return pbKey;
}
Here is the exception
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
at Main.getPublic(Main.java:40)
at Main.main(Main.java:28)
But the online PEM parser website - https://8gwifi.org/PemParserFunctions.jsp is accepting this public key, which is using bouncycastle library in the background to validate this base64 encoded public key.
The exception is thrown because the ASN.1 DER encoding of an RSA public key generated on iOS is represented with the RSAPublicKey type as defined by PKCS#1, while Java (and many other languages and tools) expect the DER encoding to be represented with the SubjectPublicKeyInfo type as defined by X.509. There are of course two sides where this problem can be solved. And if you choose to convert the DER encoding of the RSA public key at the iOS side, you could use this project I recently published on GitHub. The structure you may be interested in is RSAPublicKeyExporter, which uses the SimpleASN1Writer for converting the DER encoding. The code snippet below shows how to use it:
import RSAPublicKeyExporter
let publicKeyData = ... // Get external representation of RSA public key some how
let x509EncodedKeyData = RSAPublicKeyExporter().toSubjectPublicKeyInfo(publicKeyData)
The answer I posted here contains some information that may be useful in case the exported key is fetched from the keychain.
Thanks guys. Due to some issues with bouncycastle library, we did not used it in backend service. So in iOS, we are including ASN1 header.
struct ASN1 {
let type: UInt8
let length: Int
let data: Data
init?(type: UInt8, arbitraryData data: Data) {
guard data.count > 4 else {
return nil
}
var result = data
let byteArray = [UInt8](result)
for (_, v) in byteArray.enumerated() {
if v == type { // ASN1 SEQUENCE Type
break
}
result = Data(result.dropFirst())
}
guard result.count > 4 else {
return nil
}
guard
let first = result.advanced(by: 0).first, // advanced start from 7.0
let second = result.advanced(by: 1).first,
let third = result.advanced(by: 2).first,
let fourth = result.advanced(by: 3).first
else {
return nil
}
var length = 0
switch second {
case 0x82:
length = ((Int(third) << 8) | Int(fourth)) + 4
break
case 0x81:
length = Int(third) + 3
break
default:
length = Int(second) + 2
break
}
guard result.startIndex + length <= result.endIndex else { // startIndex, endIndex start from 7.0
return nil
}
result = result[result.startIndex..<result.startIndex + length]
self.data = result
self.length = length
self.type = first
}
var last: ASN1? {
get {
var result: Data?
var dataToFetch = self.data
while let fetched = ASN1(type: self.type, arbitraryData: dataToFetch) {
if let range = data.range(of: fetched.data) {
if range.upperBound == data.count {
result = fetched.data
dataToFetch = Data(fetched.data.dropFirst())
} else {
dataToFetch = Data(data.dropFirst(range.upperBound))
}
} else {
break
}
}
return ASN1(type: type, arbitraryData: result!)
}
}
static func wrap(type: UInt8, followingData: Data) -> Data {
var adjustedFollowingData = followingData
if type == 0x03 {
adjustedFollowingData = Data([0]) + followingData // add prefix 0
}
let lengthOfAdjustedFollowingData = adjustedFollowingData.count
let first: UInt8 = type
var bytes = [UInt8]()
if lengthOfAdjustedFollowingData <= 0x80 {
let second: UInt8 = UInt8(lengthOfAdjustedFollowingData)
bytes = [first, second]
} else if lengthOfAdjustedFollowingData > 0x80 && lengthOfAdjustedFollowingData <= 0xFF {
let second: UInt8 = UInt8(0x81)
let third: UInt8 = UInt8(lengthOfAdjustedFollowingData)
bytes = [first, second, third]
} else {
let second: UInt8 = UInt8(0x82)
let third: UInt8 = UInt8(lengthOfAdjustedFollowingData >> 8)
let fourth: UInt8 = UInt8(lengthOfAdjustedFollowingData & 0xFF)
bytes = [first, second, third, fourth]
}
return Data(bytes) + adjustedFollowingData
}
static func rsaOID() -> Data {
var bytes = [UInt8]()
bytes = [0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00]
return Data(bytes)
}
}
Then called this during generating public key of RSA in swift.
class func RSAPublicKeyBitsFromKey(_ secKey:SecKey) -> Data? {
var queryPublicKey:[String:AnyObject] = [:]
queryPublicKey[kSecClass as String] = kSecClassKey as NSString
queryPublicKey[kSecAttrKeyType as String] = kSecAttrKeyTypeRSA as NSString
if let publicKeyData = SwiftCrypto.publicKeyInData(queryPublicKey, secKey: secKey) {
let bitstringSequence = ASN1.wrap(type: 0x03, followingData: publicKeyData)
let oidData = ASN1.rsaOID()
let oidSequence = ASN1.wrap(type: 0x30, followingData: oidData)
let X509Sequence = ASN1.wrap(type: 0x30, followingData: oidSequence + bitstringSequence)
return X509Sequence
}
return nil
}
So, in this way, I had fixed this issue.

Error: "Block size and Initialization Vector must be the same length!"

I am trying to Encrypt some data and I keep getting this error,
Meanwhile my iv and key are at the same size but contain 29 values...This is my code. When I try a key with 16 values it works but I got to work with this other key too and I don't know how to solve it. Can somebody help me?
class AESHelper {
var key: String
var iv : String
let BLOCK_SIZE = AES.blockSize
init(key: String, iv: String){
self.key = key
self.iv = iv
}
func encrypt(stringToEncrypt: String) -> String {
let messageData = stringToEncrypt.dataUsingEncoding(NSUTF8StringEncoding)
let byteArray = messageData!.arrayOfBytes()
let encryptedBytes = try! AES(key: self.key, iv: self.iv, blockMode: .CBC).encrypt(byteArray, padding: PKCS7())
let toBase64 = NSData(bytes: encryptedBytes).base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
return toBase64
}