I am trying to use the UUID to generate as a nonce to be use for Twitter reverse authentication. But apparently the UUID is not a good choice. So how can I generate a unique random string every time stripping out all non-word characters, taking care that it gets release from memory after use. The following code crashes.
var uuid: CFUUIDRef = CFUUIDCreate(nil)
var nonce: CFStringRef = CFUUIDCreateString(nil, uuid)
CFRelease(uuid)
println("createdNonce:\(nonce)")
EDIT:
I am on xcode6 beta2, and i can't debug, and xocde crashes, any chance it gets. So well, the CFRelease part is crashing for me. Once I remove, it seems to work fine, but I dont know if this will create a memory leak.
As to why UUID's might not be a good choice to use for nonce it seems is because, UUID's are not made of true random bits, referring this discussion here: https://github.com/aws/aws-sdk-ios/issues/30
A more correct way of generation a nonce would probably be to generate random bytes using a cryptographic RNG. iOS just happens to have such a thing:
var s = NSMutableData(length: 32)
SecRandomCopyBytes(kSecRandomDefault, UInt(s.length), UnsafePointer<UInt8>(s.mutableBytes))
// s is now a NSData containing 32 random bytes
Then convert to a string using whatever format the API suggests (probably Base64), e.g.
let base64str = s.base64EncodedStringWithOptions(0)
EDIT: The approach above seems to be the one Twitter uses in the docs. See here. I can't say if UUIDS are more easily predicted. It depends on the method they are generated. SecRandomCopyBytes seems to be used for cryptographic purposes though, so it should be safe to use.
With SwiftUI 5.x and CryptoKit, it is easy:
import CryptoKit
let nonce = ChaChaPoly.Nonce.init()
in use:
let encryptedContent = try! ChaChaPoly.seal(inputBuffer, using: symmetricKey, nonce: ChaChaPoly.Nonce.init()).combined
One example that's provided by Firebase's Authenticating Using Apple tutorial:
// Adapted from https://auth0.com/docs/api-auth/tutorials/nonce#generate-a-cryptographically-random-nonce
private func randomNonceString(length: Int = 32) -> String {
precondition(length > 0)
let charset: Array<Character> =
Array("0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._")
var result = ""
var remainingLength = length
while remainingLength > 0 {
let randoms: [UInt8] = (0 ..< 16).map { _ in
var random: UInt8 = 0
let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &random)
if errorCode != errSecSuccess {
fatalError("Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)")
}
return random
}
randoms.forEach { random in
if remainingLength == 0 {
return
}
if random < charset.count {
result.append(charset[Int(random)])
remainingLength -= 1
}
}
}
return result
}
Your code is crashing because you are calling CFRelease.In swift there is no need to call CFRelease.From swift guide
Core Foundation objects returned from annotated APIs are automatically
memory managed in Swift—you do not need to invoke the CFRetain,
CFRelease, or CFAutorelease functions yourself.
var uuid: CFUUIDRef = CFUUIDCreate(nil)
var nonce: CFStringRef = CFUUIDCreateString(nil, uuid)
//Remove this swift will manage the memory managment.This line is causing crash
//CFRelease(uuid)
println("createdNonce:\(nonce)")
this code will work fine.No this will not create memory leak swift will manage that
Here is an answer that works in Swift 4:
func generateNonce(lenght: Int) throws -> Data {
let nonce = NSMutableData(length: lenght)
let result = SecRandomCopyBytes(kSecRandomDefault, nonce!.length, nonce!.mutableBytes)
if result == errSecSuccess {
return nonce! as Data
} else {
throw Error
}
}
This might not be a perfect solution but want to suggest it because it will take a lot of Twitter reverse auth madness for you..
Try to use cocoapod TWReverseAuth
Here is a easier way to do this then:
var temp = NSUUID.UUID().UUIDString
var nonce = temp.stringByReplacingOccurrencesOfString("-", withString: "")
println("createdNonce:\(nonce)")
Related
The input to dictionary(fromTXTRecord:) comes from the network, potentially from outside the app, or even the device. However, Apple's docs say:
... Fails an assertion if txtData cannot be represented as an NSDictionary object.
Failing an assertion leaves the programmer (me) with no way of handling the error, which seems illogic for a method that processes external data.
If I run this in Terminal on a Mac:
dns-sd -R 'My Service Name' _myservice._tcp local 4567 asdf asdf
my app, running in an iPhone, crashes.
dictionary(fromTXTRecord:) expects the TXT record data (asdf asdf) to be in key=val form. If, like above, a word doesn't contain any = the method won't be able to parse it and fail the assertion.
I see no way of solving this problem other than not using that method at all and implementing my own parsing, which feels wrong.
Am I missing something?
Here's a solution in Swift 4.2, assuming the TXT record has only strings:
/// Decode the TXT record as a string dictionary, or [:] if the data is malformed
public func dictionary(fromTXTRecord txtData: Data) -> [String: String] {
var result = [String: String]()
var data = txtData
while !data.isEmpty {
// The first byte of each record is its length, so prefix that much data
let recordLength = Int(data.removeFirst())
guard data.count >= recordLength else { return [:] }
let recordData = data[..<(data.startIndex + recordLength)]
data = data.dropFirst(recordLength)
guard let record = String(bytes: recordData, encoding: .utf8) else { return [:] }
// The format of the entry is "key=value"
// (According to the reference implementation, = is optional if there is no value,
// and any equals signs after the first are part of the value.)
// `ommittingEmptySubsequences` is necessary otherwise an empty string will crash the next line
let keyValue = record.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false)
let key = String(keyValue[0])
// If there's no value, make the value the empty string
switch keyValue.count {
case 1:
result[key] = ""
case 2:
result[key] = String(keyValue[1])
default:
fatalError()
}
}
return result
}
I'm still hoping there's something I'm missing here, but in the mean time, I ended up checking the data for correctness and only then calling Apple's own method.
Here's my workaround:
func dictionaryFromTXTRecordData(data: NSData) -> [String:NSData] {
let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes), count: data.length)
var pos = 0
while pos < buffer.count {
let len = Int(buffer[pos])
if len > (buffer.count - pos + 1) {
return [:]
}
let subdata = data.subdataWithRange(NSRange(location: pos + 1, length: len))
guard let substring = String(data: subdata, encoding: NSUTF8StringEncoding) else {
return [:]
}
if !substring.containsString("=") {
return [:]
}
pos = pos + len + 1
}
return NSNetService.dictionaryFromTXTRecordData(data)
}
I'm using Swift 2 here. All contributions are welcome. Swift 3 versions, Objective-C versions, improvements, corrections.
I just ran into this one using Swift 3. In my case the problem only occurred when I used NetService.dictionary(fromTXTRecord:) but did not occur when I switched to Objective-C and called NSNetService dictionaryFromTXTRecord:. When the Objective-C call encounters an entry without an equal sign it creates a key containing the data and shoves it into the dictionary with an NSNull value. From what I can tell the Swift version then enumerates that dictionary and throws a fit when it sees the NSNull. My solution was to add an Objective-C file and a utility function that calls dictionaryFromTXTRecord: and cleans up the results before handing them back to my Swift code.
Hello I just want to decrypt from md5 to 'normal string'
extension String {
func MD5() -> String {
var data = (self as NSString).dataUsingEncoding(NSUTF8StringEncoding)
let result = NSMutableData(length: Int(CC_MD5_DIGEST_LENGTH))
let resultBytes = UnsafeMutablePointer<CUnsignedChar>(result!.mutableBytes)
CC_MD5(data!.bytes, CC_LONG(data!.length), resultBytes)
let buff = UnsafeBufferPointer<CUnsignedChar>(start: resultBytes, count: result!.length)
let hash = NSMutableString()
for i in buff {
hash.appendFormat("%02x", i)
}
return hash as String
}
var x = "abc".MD5()
I want to get back to abc from "x"
It's not possible that's the whole point of hashing. You can however bruteforce by going through all possibilities (using all possible digits characters in every possible order) and hashing them and checking for a collision.
it was hard to reverse.
also check...https://en.wikipedia.org/wiki/MD5
Simple: Not possible, because MD5 hash is not possible to invert.
Check about One way function
Is there a way to create random unique IDs similar to the YouTube IDs in Swift?
I know there are similar answers on this link, but they are for Php. But I want something in Swift.
I have tried using timestamp and UUIDs, but I want an alphanumeric short keys which would be around 4-10 characters so users can easily share with others verbally.
Thanks.
Looking for just a unique string
You can use UUIDs they're pretty cool:
let uuid = NSUUID().UUIDString
print(uuid)
From the docs
UUIDs (Universally Unique Identifiers), also known as GUIDs (Globally
Unique Identifiers) or IIDs (Interface Identifiers), are 128-bit
values. UUIDs created by NSUUID conform to RFC 4122 version 4 and are
created with random bytes.
Some info about uuid: https://en.wikipedia.org/wiki/Universally_unique_identifier
Looking for a more specific length
Try something like this:
func randomStringWithLength(len: Int) -> NSString {
let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let randomString : NSMutableString = NSMutableString(capacity: len)
for _ in 1...len{
let length = UInt32 (letters.length)
let rand = arc4random_uniform(length)
randomString.appendFormat("%C", letters.character(at: Int(rand)))
}
return randomString
}
But i'll keep my answer incase someone else stumbles upon this looking for a UUID
This will allow you to create a random short code. It can create codes from Hexadecimal all the way to base 62 codes and of varying lengths.
aka.
let myCode = ShortCodeGenerator.getCode(length: 6)
3dH7t8,
fdE7j1,
Gl6jKd,
Hv8gU3,
let myBase32Code = ShortCodeGenerator.getCode(withBase: UInt32(32), length: 6)
3HF75J,
J67N9D,
B47SO3,
L9SD2N
You would have to check for redundancy and then create a new one if it has already been used.
struct ShortCodeGenerator {
private static let base62chars = [Character]("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".characters)
private static let maxBase : UInt32 = 62
static func getCode(withBase base: UInt32 = maxBase, length: Int) -> String {
var code = ""
for _ in 0..<length {
let random = Int(arc4random_uniform(min(base, maxBase)))
code.append(base62chars[random])
}
return code
}
}
This answer was useful in creating the above code and also has good
information on the number of unique identifiers you can have with each base number and length.
The total number of unique identifiers you need can be calculated by the equation:
BaseNumber^length = # of unique IDs
EDIT:
I have added even more functionality for converting Int's and NSDate's to shortcodes for my own project as well and put those into a project on GitHub.
Updated for swift 3:
If you want to generate Short Random Unique alphanumeric keys, used below lines of codes;
//function defination:
func generateTransactionId(length: Int) -> String {
var result = ""
let base62chars = [Character]("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".characters)
let maxBase : UInt32 = 62
let minBase : UInt16 = 32
for _ in 0..<length {
let random = Int(arc4random_uniform(UInt32(min(minBase, UInt16(maxBase)))))
result.append(base62chars[random])
}
return result
}
//function call:
let mTranactionId = self.generateTransactionId(length: 5) // you can change the value of length as you want
print("mTranactionId: \(mTranactionId)")
Ex: Result looks like: XHA7K, QTC92, MS1PT, YE2PV
//Enjoy coding...!
Does NSUUID().UUIDString do what you need?
I'm very pleased with NanoID.
https://github.com/ai/nanoid
...and here's the SWIFT version:
https://github.com/antiflasher/NanoID
You just need to drag 1 file (NanoID.swift) into your project, and you are good to go!
TAGS: Short GUID, Short UUID, Short Unique ID, Swift, iOS
Swift custom alternative(these version doesn't check for duplicate char):
func randomString(length: Int) -> String {
let letters = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
var randomString: String = ""
for _ in 0..<length {
let randomNumber = Int.random(in: 0..<letters.count)
randomString.append(letters[randomNumber])
}
return randomString
}
You can archive this just using UUID.
If you don't want the whole string, as any String in Swift, you select a small portion of the string by using range, like this:
let text = UUID().uuidString
let index = text.index(text.startIndex, offsetBy: 8)
let small = text[text.startIndex..<index]
Notice 8 is the length of string I suggested, you can improve this by clamping this value using min(size, text.count) for example.
And finally, small is a Substring, to cast it to String just cast as usual - String(small)
Swift 5 version using a String extension
extension String {
static func random(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).compactMap { _ in
letters.randomElement()
})
}
}
I am starting a project to create an iOS app to communicate with a device over BLE. Being a new effort, I am trying to do this is Swift if possible. The interface uses GATT and an existing set of custom message structures. I get to a point where I have the data from BLE in an NSData object. I'd like to cast it or directly convert it to my message structure in a fairly generic way.
I know that I can extract the data by hand either directly from the byte array from the NSData object or using an NSInputStream. While that works, it could be a maintenance issue and the interface has a number of different messages in it.
Is there an easier ways to do this?
I'd be willing to create the message structures in Objective-C and do the casting there, but my knowledge of Objective-C is not much better than my knowledge of Swift.
Some sample code of what I've been playing in my playground is shown below. It all works as expected.
func getBytesFromNSData(data: NSData, start: Int) -> [UInt8] {
let count = data.length / sizeof(UInt8)
let remaining = count - start
let range = NSMakeRange(start, remaining )
var dataArray = [UInt8](count: remaining, repeatedValue: 0)
data.getBytes(&dataArray, range: range)
return dataArray
}
class TestObject {
var a: Byte
var b: Byte
init() {
a = 0x01
b = 0x02
}
init(data: NSData) {
let dataBytes = getBytesFromNSData(data, 0)
a = Byte(dataBytes[0])
b = Byte(dataBytes[1])
}
func populateFromStream(data: NSData) {
var stream = NSInputStream(data: data)
stream.open()
var bytesRead = stream.read(&a, maxLength: 1)
println("\(bytesRead)")
bytesRead = stream.read(&b, maxLength: 1)
println("\(bytesRead)")
}
func toArray() -> [Byte] {
var result = [Byte](count: 2, repeatedValue: 0)
result[0] = a
result[1] = b
return result
}
}
let test = TestObject()
let testArray = test.toArray()
let length = testArray.count
let testData = NSData(bytes: testArray, length: length)
println("\(testData)")
let testIn = [ Byte(0x0d), Byte(0x0e) ]
let testDataIn = NSData(bytes: testIn, length: testIn.count)
println("\(testDataIn)")
let testConstructor = TestObject(data: testDataIn)
var testObject = TestObject()
testObject.populateFromStream(testDataIn)
I found a method that is fairly generic that may work is some cases.
Create an Objective-C riding header
Create the data structure as an Objective-C structure
Import the header with the data structure into the bridging header
Assuming that you have a struct called Foo and an NSData object called rawData:
Use the following code to get an cast a pointer.
let structureSize = sizeof(Foo)
var myObject = UnsafeMutablePointer<Foo>.alloc(1).memory
rawData.getbytes(&myObject, length: structureSize)
This will not work in all instances and unfortunately does work in my particular case. The specific problems I have found are:
The Objective-C structure is word aligned. If your structure is not properly aligned to work boundaries, you may have a size that is incorrect. (something I ran into in my particular interface)
If you and dealing with a system that doesn't send the data in the same order you are expecting, this will not handle any byte order conversion, that would still need to be done and the structure would possibly need to be reordered to compensate. That work might negate any saving from this method.
This is the most concise method I have found if it happens to work with your particular message formats.
I am interested in creating a modified encoded UUID but I am having a heck of a time getting the right format. What I currently have does not compile for reasons unknown but oddly Im able to run it in a playground. Here is the function:
class func genID() -> String {
let uuid = NSUUID.UUID()
let data = NSData(bytes:&uuid, length:16)
let base64 = data.base64EncodedStringWithOptions(nil)
let options = NSStringCompareOptions.LiteralSearch
let result = base64
.stringByReplacingOccurrencesOfString("/", withString: "-", options: options, range: nil)
.stringByReplacingOccurrencesOfString("+", withString: "_", options: options, range: nil)
.stringByReplacingOccurrencesOfString("=", withString: "", options: options, range: nil)
return result
}
The problem is flagged on the second line of the function; the creation of the data value. Strangely that line does work in a playground. Any help would be appreciated. So what am I missing here?
Thanks in advance.
You can create an NSData object from NSUUID with
let uuid = NSUUID.UUID()
// data object with appropriate size:
let data = NSMutableData(length: 16)
// fill the bytes from the UUID:
uuid.getUUIDBytes(UnsafeMutablePointer(data.mutableBytes))
I was able to do this without using NSUUID by converting the uuid_t type to a Data object. This type is an alias for a 16-byte tuple. Looks a little strange in the implementation, but it works, and this is fairly future proof if for some reason the uuid_t type changes. Here's the UUID extension I created:
import Foundation
extension UUID {
var base64String: String {
return self.data.base64EncodedString()
}
var data: Data {
var result = Data()
let uuidTuple = self.uuid
// NOTE: There are clever ways to iterate over a tuple in Swift,
// but I actually want this to not compile if the implementation of uuid_t
// changes in the future
result.append(uuidTuple.0)
result.append(uuidTuple.1)
result.append(uuidTuple.2)
result.append(uuidTuple.3)
result.append(uuidTuple.4)
result.append(uuidTuple.5)
result.append(uuidTuple.6)
result.append(uuidTuple.7)
result.append(uuidTuple.8)
result.append(uuidTuple.9)
result.append(uuidTuple.10)
result.append(uuidTuple.11)
result.append(uuidTuple.12)
result.append(uuidTuple.13)
result.append(uuidTuple.14)
result.append(uuidTuple.15)
return result
}
}