SecKeyRawSign returning error -1, "generic error"? - swift

I am working on an iOS application that needs to generate a key pair on the device, store the private key in the Secure Enclave, and then access it later to use for signing (does not need to be exported, ever). When I sign, I always hash the data using SHA256, following a couple of stack Overflow answers, and it seems to be working when I print the results. However, after obtaining a valid private key reference from the KeyChain, hashing the data to be signed, and specifying that it is a SHA256 hash, SecKeyRawSign still returns -1. This is just listed as a 'generic error', and my setup seems like it should be valid. Some insight on what's going wrong would be greatly appreciated. Here are my methods to generate and sign:
private func genKeyPair() -> (privateAlias: String, publicKey: NSData)? {
// Generate a keyhandle, which will be returned as an alias for the private key
let numBytes = Int(keyHandleLength)
var randomBytes = [UInt8](count: numBytes, repeatedValue: 0)
SecRandomCopyBytes(kSecRandomDefault, numBytes, &randomBytes)
let data = NSData(bytes: &randomBytes, length: numBytes)
let alias = data.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let access = SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, .TouchIDCurrentSet, nil)!
// Key pair parameters
var keyParams: [String:AnyObject] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256
]
// Private key parameters
keyParams[kSecPrivateKeyAttrs as String] = [
kSecAttrIsPermanent as String: true,
kSecAttrLabel as String: alias,
kSecAttrApplicationTag as String: applicationTag,
kSecAttrAccessControl as String: access
]
// Public key parameters
keyParams[kSecPublicKeyAttrs as String] = [
kSecAttrIsPermanent as String: true,
kSecAttrLabel as String: alias + "-pub",
kSecAttrApplicationTag as String: applicationTag
]
var pubKeyRef, privKeyRef: SecKey?
var err = SecKeyGeneratePair(keyParams, &pubKeyRef, &privKeyRef)
guard let _ = pubKeyRef where err == errSecSuccess else {
print("Error while generating key pair: \(err).")
return nil
}
// Export the public key for application use
let query = [
kSecClass as String: kSecClassKey,
kSecAttrLabel as String: alias + "-pub",
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnData as String: true
]
var pubKeyOpt: AnyObject?
err = SecItemCopyMatching(query, &pubKeyOpt)
if let pubKey = pubKeyOpt as? NSData where err == errSecSuccess {
print("Successfully retrieved public key!")
return (alias, pubKey)
} else {
print("Error retrieving public key: \(err).")
return nil
}
}
private func sign(bytes data: NSData, usingKeyWithAlias alias: String) -> NSData? {
let query = [
kSecClass as String: kSecClassKey,
kSecAttrLabel as String: alias,
kSecAttrApplicationTag as String: applicationTag,
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecReturnRef as String: true
]
var privateKey: AnyObject?
var error = SecItemCopyMatching(query, &privateKey)
guard error == errSecSuccess else {
print("Could not obtain reference to private key with alias \"\(alias)\", error: \(error).")
return nil
}
print("\nData: \(data)")
print("Length: \(data.length)")
let hashedData = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH))!
CC_SHA256(data.bytes, CC_LONG(data.length), UnsafeMutablePointer(hashedData.mutableBytes))
print("\nHashed data: \(hashedData)")
print("Length: \(hashedData.length)")
var signedHashLength = SecKeyGetBlockSize(privateKey as! SecKeyRef)
let signedHash = NSMutableData(length: signedHashLength)!
error = SecKeyRawSign(privateKey as! SecKeyRef, .PKCS1SHA256, UnsafePointer<UInt8>(hashedData.mutableBytes), hashedData.length, UnsafeMutablePointer<UInt8>(signedHash.mutableBytes), &signedHashLength)
print("\nSigned hash: \(signedHash)")
print("Length: \(signedHashLength)\n")
guard error == errSecSuccess else {
print("Failed to sign data, error: \(error).")
return nil
}
return signedHash
}

Related

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.

Is there a way to use guard statements more concisely?

I'm using Gloss for my JSON instantiation. Here is a sample class:
public class MyObj: Decodable
{
let id_user : String
let contact_addr1 : String
let contact_addr2 : String?
let contact_city : String
let contact_state : String
let contact_zip : String
let points : Int
// Deserialization
required public init?(json: JSON)
{
guard let id_user : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_addr1 : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_city : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_state : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let contact_zip : String = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
guard let points : Int = "somekey" <~~ json else {
assertionFailure("MyObj - invalid JSON. Missing key: wouldbenicetonotwritethisforeachmember")
return nil
}
self.id_user = id_user
self.contact_addr1 = contact_addr1
self.contact_addr2 = "somekey" <~~ json
self.contact_city = contact_city
self.contact_state = contact_state
self.contact_zip = contact_zip
self.contact_points = points
}
}
I have a lot of model classes. Hundreds of members between them. Writing a multi-line guard statement for each one really junks up my code. Is there any way I can encapsulate the guard functionality into something more concise? Maybe a function or something like:
shortGuard("memberName", "jsonKey")
Maybe there is a way to guard against an array of string keys?
There are a huge variety of ways to accomplish this. They all boil down to writing a wrapper function to map your keys to values. Here are a couple quick examples I thought of, but as I say there are many ways to do this depending on what you're after:
enum JSONError: Error {
case keyNotFound(String)
}
extension JSON {
func values<T>(for keys: [String]) throws -> [T] {
var values = [T]()
for key in keys {
guard let value: T = key <~~ self else {
throw JSONError.keyNotFound(key)
}
values.append(value)
}
return values
}
func values<T>(for keys: [String], closure: ((_ key: String, _ value: T) -> Void)) throws {
for key in keys {
guard let value: T = key <~~ self else {
throw JSONError.keyNotFound(key)
}
closure(key, value)
}
}
}
The first validates all keys before you can use any of them and will throw if one isn't present. You'd use it like so:
do {
let keys = ["foo", "bar"]
// The type of the values constant is important.
// In this example we're saying look for values of type Int.
let values: [Int] = try json.values(for: keys)
for (index, key) in keys.enumerated() {
print("value for \(key): \(values[index])")
}
} catch JSONError.keyNotFound(let key) {
assertionFailure("key not found \(key)")
}
The second one will pass back key, value pairs to a closure as they appear in your keys array and will throw at the first one it finds that doesn't exist.
do {
let keys = ["foo", "bar"]
// The type of the closure's value argument is important.
// In this example we're saying look for values of type String.
try json.values(for: keys) { (key, value: String) in
print("value for key \(key) is \(value)")
}
} catch JSONError.keyNotFound(let key) {
assertionFailure("key not found \(key)")
}
Using the first version in an init?() function for your class, we have something like this:
public struct MyObj: Decodable {
public let id_user : String
public let contact_addr1 : String
public let contact_addr2 : String?
public let points : Int
public init?(json: S) {
do {
let stringKeys = ["id_user", "contact_addr1"]
let stringValues: [String] = try json.values(for: stringKeys)
id_user = stringValues[0]
contact_addr1 = stringValues[1]
// this isn't required, so just extract with no error if it fails
contact_addr2 = "contact_addr2" <~~ json
let intKeys = ["points"]
let intValues: [Int] = try json.values(for: intKeys)
points = intValues[0]
} catch JSONError.keyNotFound(let key) {
assertionFailure("key \(key) not found in JSON")
return nil
} catch {
return nil
}
}
}
I have not used Gloss, and it mostly seems to be unnecessary considering that it is simple enough to parse JSON safely without needing an extra library, or using unfamiliar syntax.
Option 1:
You can group the optional unwrapping in a single guard statement.
Example:
public struct MyObj {
let id_user : String
let contact_addr1 : String
let contact_addr2 : String?
let points : Int
public init?(json: Any) {
guard
let entities = json as? [String : Any],
let id_user = entities["some key"] as? String,
let contact_addr1 = entities["some key"] as? String,
let points = entities["some key"] as? Int
else {
assertionFailure("...")
return nil
}
self.id_user = id_user
self.contact_addr1 = contact_addr1
self.contact_addr2 = entities["some key"] as? String
self.contact_points = points
}
}
Option 2:
Another approach would be to eliminate the guard statements altogether, and let the parser throw an error during parsing, and use an optional try to convert the result to nil.
Example:
// Helper object for parsing values from a dictionary.
// A similar pattern could be used for arrays. i.e. array.stringAt(10)
struct JSONDictionary {
let values: [String : Any]
init(_ json: Any) throws {
guard let values = json as? [String : Any] else {
throw MyError.expectedDictionary
}
self.values = values
}
func string(_ key: String) throws -> String {
guard let value = values[key] as? String else {
throw MyError.expectedString(key)
}
return value
}
func integer(_ key: String) throws -> Int {
guard let value = values[key] as? Int else {
throw MyError.expectedInteger(key)
}
return value
}
}
Parser:
public struct MyObj {
let id_user : String
let contact_addr1 : String
let contact_addr2 : String?
let points : Int
public init(json: Any) throws {
// Instantiate the helper object.
// Ideally the JSONDictionary would be passed by the caller.
let dictionary = try JSONDictionary(json),
self.id_user = try dictionary.string("some key"),
self.contact_addr1 = try dictionary.string("some key"),
self.points = try dictionary.integer("some key")
// Results in an optional if the string call throws an exception
self.contact_addr2 = try? dictionary.string("some key")
}
}
Usage:
// Instantiate MyObj from myJSON.
// myObject will be nil if parsing fails.
let myObject = try? MyObj(json: myJSON)

[Swift._NSContiguousString bytes]: unrecognized selector sent to instance

I'm working on Xcode version 7.1 (7B91b), I'm using Swift and building an OSX application (10.11.2). I'm trying to generate and store RSA key pairs to be used for data encryption / decryption. Here's the implementation that has been taken from: 'AsymmetricCrypto Github
// Constants
private let kAsymmetricCryptoManagerApplicationTag = "com.AsymmetricCrypto.keypair"
private let kAsymmetricCryptoManagerKeyType = kSecAttrKeyTypeRSA
private let kAsymmetricCryptoManagerKeySize = 2048
private let kAsymmetricCryptoManagerCypheredBufferSize = 1024
private let kAsymmetricCryptoManagerSecPadding: SecPadding = .PKCS1
func createSecureKeyPair(completion: ((success: Bool, error: AsymmetricCryptoException?) -> Void)? = nil) {
// private key parameters
let privateKeyParams: [String: AnyObject] = [
kSecAttrIsPermanent as String: false,
kSecAttrApplicationTag as String: kAsymmetricCryptoManagerApplicationTag
]
// private key parameters
let publicKeyParams: [String: AnyObject] = [
kSecAttrIsPermanent as String: false,
kSecAttrApplicationTag as String: kAsymmetricCryptoManagerApplicationTag
]
// global parameters for our key generation
let parameters: [String: AnyObject] = [
kSecAttrKeyType as String: kAsymmetricCryptoManagerKeyType,
kSecAttrKeySizeInBits as String: kAsymmetricCryptoManagerKeySize,
kSecPublicKeyAttrs as String: publicKeyParams,
kSecPrivateKeyAttrs as String: privateKeyParams,
]
// asynchronously generate the key pair and call the completion block
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
var pubKey, privKey: SecKeyRef?
let status = SecKeyGeneratePair(parameters, &pubKey, &privKey)
if status == errSecSuccess {
dispatch_async(dispatch_get_main_queue(), { completion?(success: true, error: nil) })
} else {
var error = AsymmetricCryptoException.UnknownError
switch (status) {
case errSecDuplicateItem: error = .DuplicateFoundWhileTryingToCreateKey
case errSecItemNotFound: error = .KeyNotFound
case errSecAuthFailed: error = .AuthFailed
default: break
}
dispatch_async(dispatch_get_main_queue(), { completion?(success: false, error: error) })
}
}
}
Upon calling the createSecureKeyPair(), as follows:
AsymmetricCryptoManager.sharedInstance.createSecureKeyPair({
(success, error) -> Void in
if (success) {
print("keys created")
} else {
print("error: \(error)")
}
})
I get this error:
2015-12-26 03:55:46.113 sectest[17165:20928431] -[Swift._NSContiguousString bytes]: unrecognized selector sent to instance 0x610000045880
and of course, the exception AsymmetricCryptoException.UnknownError is returned (meaning that the error is of an unknown nature), plus if it helps, SecKeyGeneratePair() returns the value -2070
The weird part is that the keys (public and private) are actually created in the Keychain as such:
What is this error and how can get the expected behavior out of the code above?
I got the answer to the problem from the Apple Developer Forums. The problem is with:
private let kAsymmetricCryptoManagerApplicationTag = "com.AsymmetricCrypto.keypair"
The values for key kSecAttrApplicationTag of params dictionaries need to be a CFDataRef, not String. The below line, resolves the problem.
private let kAsymmetricCryptoManagerApplicationTag = "com.sectest.keypair".dataUsingEncoding(NSUTF8StringEncoding)!

Create JSON String from Array?

This might be an easy question, but how can I create a simple JSON String from an existing Array?
In the Documentation the only thing I found is:
class func JSONObjectWithData(_ data: NSData,
options opt: NSJSONReadingOptions,
error error: NSErrorPointer) -> AnyObject?
But I only want to create a simple JSON String from an existing Array.
With the existing Swift JSON Extensions I am only able to parse existing JSON Strings, and could not create a new String.
I could manually create the String, but there might be a better solution.
Any help would be greatly appreciated.
If you have a NSArray object, you could create your JSON String by using something like:
func JSONStringify(value: AnyObject, prettyPrinted: Bool = false) -> String {
var options = prettyPrinted ? NSJSONWritingOptions.PrettyPrinted : nil
if NSJSONSerialization.isValidJSONObject(value) {
if let data = NSJSONSerialization.dataWithJSONObject(value, options: options, error: nil) {
if let string = NSString(data: data, encoding: NSUTF8StringEncoding) {
return string
}
}
}
return ""
}
I found here the details for this function.
SWIFT 3
func JSON2String(jsonObj: AnyObject, prettyPrinted: Bool = false) -> String {
let options = prettyPrinted ? JSONSerialization.WritingOptions.prettyPrinted : []
if JSONSerialization.isValidJSONObject(jsonObj) {
if let data = try? JSONSerialization.data(withJSONObject: jsonObj, options: options) {
if let string = String(data: data, encoding: Task.StringEncoding) {
return string
}
}
}
return ""
}
Let's say you have an array of Strings called array. You would do this:
let array = [ "String1", "String2" ]
var error:NSError?
let data = NSJSONSerialization.dataWithJSONObject(array, options: NSJSONWritingOptions.allZeros, error: &error)
let str = NSString(data:data!, encoding:NSUTF8StringEncoding)
println("\(str!)")