Trying to generate a client Id, based on 2 unique strings.
This should end up being the same UUID as generated in the server, from same I'ds.
With Javascript it looks something like this:
uuidv5(id1 + id2 , uuidv5.DNS);
Can't seem to find a way of generating this on Swift, NSUUID only can generate a UUID from nothing
NSUUID().uuidString
I am looking for something like this:
NSUUID(namespace: id1 + id2).uuidString
Edit
Example:
let sorted = ["5a23dbfb2626b400190998fc", "5pCAvA7h8k9JuErRn"]
let appended = sorted.seperaredStringBy("-")
let result = uuidv5(appended , uuidv5.DNS)
//results:
2522b097-8532-548e-a18b-9366c6511b5e
The Swift standard library or the Foundation framework have no built-in method for version 5 UUIDs, as far as I know.
Here is a possible implementation for version 3 and version 5 UUIDs, taken from the description at Generating v5 UUID. What is name and namespace? and the reference implementation in RFC 4122.
(Updated for Swift 4 and later.)
import Foundation
import CommonCrypto
extension UUID {
enum UUIDVersion: Int {
case v3 = 3
case v5 = 5
}
enum UUIDv5NameSpace: String {
case dns = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
case url = "6ba7b811-9dad-11d1-80b4-00c04fd430c8"
case oid = "6ba7b812-9dad-11d1-80b4-00c04fd430c8"
case x500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8"
}
init(version: UUIDVersion, name: String, nameSpace: UUIDv5NameSpace) {
// Get UUID bytes from name space:
var spaceUID = UUID(uuidString: nameSpace.rawValue)!.uuid
var data = withUnsafePointer(to: &spaceUID) { [count = MemoryLayout.size(ofValue: spaceUID)] in
Data(bytes: $0, count: count)
}
// Append name string in UTF-8 encoding:
data.append(contentsOf: name.utf8)
// Compute digest (MD5 or SHA1, depending on the version):
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) -> Void in
switch version {
case .v3:
_ = CC_MD5(ptr.baseAddress, CC_LONG(data.count), &digest)
case .v5:
_ = CC_SHA1(ptr.baseAddress, CC_LONG(data.count), &digest)
}
}
// Set version bits:
digest[6] &= 0x0F
digest[6] |= UInt8(version.rawValue) << 4
// Set variant bits:
digest[8] &= 0x3F
digest[8] |= 0x80
// Create UUID from digest:
self = NSUUID(uuidBytes: digest) as UUID
}
}
Example 1 (Your case):
let uuid = UUID(version: .v5, name: "5a23dbfb2626b400190998fc-5pCAvA7h8k9JuErRn", nameSpace: .dns)
print(uuid) // 2522B097-8532-548E-A18B-9366C6511B5E
Example 2 (From Appendix B in RFC 4122, as corrected in the Errata):
let uuid = UUID(version: .v3, name: "www.widgets.com", nameSpace: .dns)
print(uuid) //3D813CBB-47FB-32BA-91DF-831E1593AC29
the objc version, in case someone need it.
+ (CBUUID *)UUIDWithNamespace:(NSString *)namespace name:(NSString *)name version:(int)version
{
if (namespace.length <= 0 || name == nil ) { return nil; }
if (!(version == 3 || version == 5)) { return nil; }
CBUUID *namespaceUUID = [CBUUID UUIDWithString:namespace];
if (namespaceUUID == nil) { return nil; }
NSMutableData *data = [[NSMutableData alloc] init];
[data appendData:namespaceUUID.data];
[data appendData:[name dataUsingEncoding:NSUTF8StringEncoding]];
unsigned char hash[CC_SHA1_DIGEST_LENGTH];
if (version == 3) {
CC_MD5(data.bytes, (int)data.length, hash);
} else if (version == 5) {
CC_SHA1(data.bytes, (int)data.length, hash);
}
unsigned char result[16];
memcpy(result, hash, 16);
result[6] &= 0x0F;
result[6] |= (((unsigned char)version) << 4);
result[8] &= 0x3F;
result[8] |= 0x80;
return [CBUUID UUIDWithData:[NSData dataWithBytes:result length:16]];
}
Related
I did generate a signature using the below code but, I want a signature in IEEE P1336 (length 80) format
guard let signData = SecKeyCreateSignature(
key,
SecKeyAlgorithm.ecdsaSignatureMessageX962SHA256,
signatureString.data(using: .utf8)! as CFData, &error) else {
let e = error!.takeRetainedValue() as Error
print("Signing Error \( e.localizedDescription)")
return nil
}
let signedData = signData as Data
let signedString = signedData.base64EncodedString(options: [])
I am not an expert in iOS. But I fixed this issue for a signature generated by iOS. You can create this format by your own. e.g. for SHA-256 hashed signature. JavaScript sample
function parseASN1ToIEEEP1363(signature) {
const buffer = new ArrayBuffer(signature.length);
const int8View = new Int8Array(buffer);
for (let i = 0, strLen = signature.length; i < strLen; i++) {
int8View[i] = signature.charCodeAt(i);
}
//Currently these bytes getting for SHA256. for other hashings need to make it dynamic
const r = new Int8Array(buffer.slice(4, 36));
const s = new Int8Array(buffer.slice(39));
return appendBuffer(r, s);
}
function appendBuffer(buffer1, buffer2) {
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
tmp.set(new Uint8Array(buffer1), 0);
tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
return tmp;
};
I have a small project where I have a list with questions (96 questions).
I try to serialize that list of questions into a BinaryData and to save that result in CoreData.
After I want to deserialize that BinaryData from CoreData and to map the values to an object.
The problem is that my serialization I think is working, but the deserialization is not working for some reason.
This line of code is not called when I run the code and I don't know why:
https://github.com/tygruletz/AddTagsForRows/blob/master/PreloadQuestions/Controller/Communication/TTable.swift#L457
To generate a report in CoreData just click Next-> Next-> Finish.
Here is the code for deserialization:
func deStreamBin(stream: InputStream, format: EStreamFormat){
var protocolByte: UInt8 = 0
var columns: UInt16 = 0
var rows: UInt32 = 0
var tableFlag: ETableFlags
//We should scroll through 0's until we find '1' indicating the start of a table
while protocolByte != 0x01 {
protocolByte = deserializeByte(stream: stream)
}
// Header
_ = deserializeUInt32(stream: stream)
columns = deserializeUInt16(stream: stream)
rows = deserializeUInt32(stream: stream)
print("Number of rows in TTable: \(rows)")
tableFlag = ETableFlags(rawValue: UInt(deserializeUInt16(stream: stream))) ?? ETableFlags.none // 0x0001 = Exception, 0x002 = Interrupt
_ = deserializeByte(stream: stream) // Flags (0x01 = Meta, 0x02 = Last Row, 0x00 = The rest)
// Read the Meta Details
var tMeta: [TMeta] = []
for _ in 0..<columns {
guard let type = EMeta(rawValue: deserializeString(stream: stream, length: 1)) else {return}
var name = ""
if format == EStreamFormat.bin1 {
let nameLength = Int(deserializeByte(stream: stream))
name = deserializeString(stream: stream, length: nameLength)
}
else{
// No names for the bin2
}
tMeta.append(TMeta(type: type, name: name))
}
self.tMeta = tMeta
self.flags = tableFlag
for _ in 0..<rows {
let row: TRow = TRow(tMeta: tMeta)
_ = deserializeUInt32(stream: stream) // Row Number
_ = deserializeByte(stream: stream) // Flags (0x01 = Meta, 0x02 = Last Row, 0x00 = The rest)
for i in 0..<tMeta.count {
let m: TMeta = tMeta[i]
switch m.type {
// Integer (Int32)
case EMeta.i:
row.cell[i] = TCell(i: Int(deserializeInt32(stream: stream)))
// Boolean
case EMeta.b:
row.cell[i] = TCell(b: deserializeBoolean(stream: stream))
// String (length as UInt32, followed by array of chars)
case EMeta.s:
let nLenString = Int(deserializeUInt32(stream: stream))
row.cell[i] = TCell(s: deserializeString(stream: stream, length: nLenString))
// DateTime (BCD Array: YY YY MM DD hh mm ss)
case EMeta.t:
row.cell[i] = TCell(date: deserializeDateTime(stream: stream) ?? Date())
// Database Bytes (Length as Int32, followed by array of bytes)
case EMeta.z:
let nLenBytes = Int(deserializeUInt32(stream: stream))
row.cell[i] = TCell(data: deserializeByteArray(stream: stream, lenght: Int32(nLenBytes)))
// Double (IEEE 8-byte double)
case EMeta.d:
row.cell[i] = TCell(d: deserializeDouble(stream: stream))
// Single Byte
case EMeta.u:
row.cell[i] = TCell(b: deserializeByte(stream: stream))
}
}
do {
try add(row: row)
} catch{
print("deStreamBin: Can't add the row in tMeta: \(error)")
}
}
}
Please help me to deserialize my BinaryData to be able to map the values to an object.
Thanks in advance !
Hi I am converting existing swift 2.0 code to swift 3.0 but came across an error while conversion:
Cannot invoke initializer for type 'UnsafePointer' with an argument list of type '(UnsafeRawPointer)'
Here is my code:
extension Data {
var hexString : String {
let buf = UnsafePointer<UInt8>(bytes) // here is the error
let charA = UInt8(UnicodeScalar("a").value)
let char0 = UInt8(UnicodeScalar("0").value)
func itoh(_ i: UInt8) -> UInt8 {
return (i > 9) ? (charA + i - 10) : (char0 + i)
}
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: count * 2)
for i in 0..<count {
p[i*2] = itoh((buf[i] >> 4) & 0xF)
p[i*2+1] = itoh(buf[i] & 0xF)
}
return NSString(bytesNoCopy: p, length: count*2, encoding: String.Encoding.utf8.rawValue, freeWhenDone: true)! as String
}
}
In Swift 3 you have to use withUnsafeBytes() to access the raw bytes of a Data value. In your case:
withUnsafeBytes { (buf: UnsafePointer<UInt8>) in
for i in 0..<count {
p[i*2] = itoh((buf[i] >> 4) & 0xF)
p[i*2+1] = itoh(buf[i] & 0xF)
}
}
Alternatively, use the fact that Data is a collection of bytes:
for (i, byte) in self.enumerated() {
p[i*2] = itoh((byte >> 4) & 0xF)
p[i*2+1] = itoh(byte & 0xF)
}
Note that there is another problem in your code:
NSString(..., freeWhenDone: true)
uses free() to release the memory, which means that it must be
allocated with malloc().
Other (shorter, but potentially less efficient) methods to create
a hex representation of a Data value can be found at
How to convert Data to hex string in swift.
I have a TI sensor Tag as a peripheral that broadcasts BLE data in the form of kCBAdvDataManufacturerData. I would like to extract different values from this data in iOS.
I am executing the following in Swift:
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
for (index, foundPeripheral) in peripherals.enumerated(){
if foundPeripheral.peripheral?.identifier == peripheral.identifier{
peripherals[index].lastRSSI = RSSI
print("AdvertisementData:\(advertisementData)")
return
}
}
let isConnectable = advertisementData["kCBAdvDataIsConnectable"] as! Bool
let displayPeripheral = DisplayPeripheral(peripheral: peripheral, lastRSSI: RSSI, isConnectable: isConnectable)
peripherals.append(displayPeripheral)
tableView.reloadData()
}
}
And this is what I see in the console:
AdvertisementData:["kCBAdvDataIsConnectable": 0, "kCBAdvDataManufacturerData": <0d00fe05 0c6f32>, "kCBAdvDataLocalName": CLIMBC]
The data that I am interested in decoding is kCBAdvDataManufacturerData : <0d00fe05 0c6f32> and displaying each field on the screen.
Specifically, this is what the numbers represent in my case:
0d00 - TI manufacturer ID
fe - the node ID that I have given
05 - state of the node (something that remains constant
c6f - is the sensor tag battery voltage
32- is the BLE packet counter.
In Android I am able to decode as following:
private static String getNodeIdFromRawPacket(byte[] manufSpecField) {
if(manufSpecField != null && manufSpecField.length > 1) {
return String.format("%02X", manufSpecField[0]);
}else{
return null;
}
}
private static int getNodeBatteryVoltageFromRawPacket(byte[] manufSpecField){
if(manufSpecField != null && manufSpecField.length > 4) {
return (((((int) manufSpecField[manufSpecField.length - 3]) << 24) >>> 24) << 8) + ((((int) manufSpecField[manufSpecField.length - 2]) << 24) >>> 24);
}else{
return 0;
}
}
private byte[] extractManufacturerSpecificData(byte[] scanRecord, int manufacturer_id){
if(scanRecord != null) {
int ptr = 0;
while (ptr < scanRecord.length && scanRecord[ptr] != 0) {
int field_length = scanRecord[ptr];
if (scanRecord[ptr + 1] == (byte) (0xFF)) { //this is true when the manufacturer specific data field has been found
if (((scanRecord[ptr + 3] << 8) + scanRecord[ptr + 2]) == manufacturer_id) {
byte[] manufacturerSpecificData = new byte[field_length - 3];
System.arraycopy(scanRecord, ptr + 4, manufacturerSpecificData, 0, field_length - 3);
return manufacturerSpecificData;
}
}
ptr += (field_length + 1);
}
return null;
}else{
return null;
}
}
};
How exactly can I achieve this? I am new to Swift that is why I am finding some difficulties. Any code snippet will be most welcome.
Seeing the output of your console, advertisementData["kCBAdvDataManufacturerData"] seems to be an NSData containing 7 bytes. You can easily access it as a Swift Data, and each byte in a Data can be accessed with subscript:
if let manufacturerData = advertisementData["kCBAdvDataManufacturerData"] as? Data {
assert(manufacturerData.count >= 7)
//0d00 - TI manufacturer ID
//Constructing 2-byte data as little endian (as TI's manufacturer ID is 000D)
let manufactureID = UInt16(manufacturerData[0]) + UInt16(manufacturerData[1]) << 8
print(String(format: "%04X", manufactureID)) //->000D
//fe - the node ID that I have given
let nodeID = manufacturerData[2]
print(String(format: "%02X", nodeID)) //->FE
//05 - state of the node (something that remains constant
let state = manufacturerData[3]
print(String(format: "%02X", state)) //->05
//c6f - is the sensor tag battery voltage
//Constructing 2-byte data as big endian (as shown in the Java code)
let batteryVoltage = UInt16(manufacturerData[4]) << 8 + UInt16(manufacturerData[5])
print(String(format: "%04X", batteryVoltage)) //->0C6F
//32- is the BLE packet counter.
let packetCounter = manufacturerData[6]
print(String(format: "%02X", packetCounter)) //->32
}
Here is an implementation of swift 3 Data method subdata with an example of a string converted to data and then split out to bytes that you can convert back to strings:
let input = "505450578"
let data = input.data(using: .utf8)
let manufacturerId:Range<Int> = 0..<2
let nodeId:Range<Int> = 2..<4
let nodeState:Range<Int> = 4..<5
let voltage:Range<Int> = 5..<6
let packetCounter:Range<Int> = 6..<9
let subdata1 = data?.subdata(in: manufacturerId)
let subdata2 = data?.subdata(in: nodeId)
let subdata3 = data?.subdata(in: nodeState)
let subdata4 = data?.subdata(in: voltage)
let subdata5 = data?.subdata(in: packetCounter)
//Results from original given string
let str1 = String(data: subdata1!, encoding:.utf8) //50
let str2 = String(data: subdata2!, encoding:.utf8) //54
let str3 = String(data: subdata3!, encoding:.utf8) //5
let str4 = String(data: subdata4!, encoding:.utf8) //0
let str5 = String(data: subdata5!, encoding:.utf8) //578
Updated for Swift:
let yourServiceUUIDString = "FFF0"
if let mAdvData = advertisementData["kCBAdvDataServiceUUIDs"] as? [AnyObject], (mAdvData.contains { ($0 as? CBUUID)?.uuidString == yourServiceUUIDString}) {
print("BLE device found..!")
}
Working in Apple Swift for iOS. I have to generate this for the backend as it's a secure app.
I'm new to security and certificates and have been searching for a day now with no results.
How can I generate base64 url-encoded X.509 format 2048-bit RSA public key with swift?
Any help is highly appreciated.
There's a library for handling public-private key pairs in Swift that I recently created called Heimdall, which allows you to easily export the X.509 formatted Base64 string of the public key.
To comply with SO rules, I will also include the implementation in this answer (so that it is self-explanatory)
public func X509PublicKey() -> NSString? {
// Fetch the key, so that key = NSData of the public key
let result = NSMutableData()
let encodingLength: Int = {
if key.length + 1 < 128 {
return 1
} else {
return ((key.length + 1) / 256) + 2
}
}()
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 + key.length
let encodedSize = encodeLength(size)
builder.extend(encodedSize)
result.appendBytes(builder, length: builder.count)
result.appendBytes(OID, length: OID.count)
builder.removeAll(keepCapacity: false)
builder.append(0x03)
builder.extend(encodeLength(key.length + 1))
builder.append(0x00)
result.appendBytes(builder, length: builder.count)
// Actual key bytes
result.appendData(key)
// Convert to Base64 and make safe for URLs
var string = result.base64EncodedStringWithOptions(.allZeros)
string = string.stringByReplacingOccurrencesOfString("/", withString: "_")
string = string.stringByReplacingOccurrencesOfString("+", withString: "-")
return string
}
public func encodeLength(length: Int) -> [CUnsignedChar] {
if length < 128 {
return [CUnsignedChar(length)];
}
var i = (length / 256) + 1
var len = length
var result: [CUnsignedChar] = [CUnsignedChar(i + 0x80)]
for (var j = 0; j < i; j++) {
result.insert(CUnsignedChar(len & 0xFF), atIndex: 1)
len = len >> 8
}
return result
}
I have removed the data fetching code, refer to either source of Heimdall or Jeff Hay's answer
If the public key is already in your keychain, you can look up the public key and return the data as base64 with something similar to the following:
// Create dictionary to specify attributes for the key we're
// searching for. Swift will automatically bridge native values
// to to right types for the SecItemCopyMatching() call.
var queryAttrs = [NSString:AnyObject]()
queryAttrs[kSecClass] = kSecClassKey
queryAttrs[kSecAttrApplicationTag] = publicKeyTag
queryAttrs[kSecAttrKeyType] = kSecAttrKeyTypeRSA
queryAttrs[kSecReturnData] = true
var publicKeyBits = Unmanaged<AnyObject>?()
SecItemCopyMatching(queryAttrs, &publicKeyBits)
// Work around a compiler bug with Unmanaged<AnyObject> types
// the following two lines should simply be
// let publicKeyData : NSData = publicKeyRef!.takeRetainedValue() as NSData
let opaqueBits = publicKeyBits?.toOpaque()
let publicKeyData = Unmanaged<NSData>.fromOpaque(opaqueBits).takeUnretainedValue()
let publicKeyBase64 = publicKeyData.base64EncodedData(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
If you need to generate the keypair and store it in the keychain, use something along these lines:
// Create dictionaries to specify key attributes. Swift will
// automatically bridge native values to to right types for the
// SecKeyGeneratePair() call.
var pairAttrs = [NSString:AnyObject]()
var privateAttrs = [NSString:AnyObject]()
var publicAttrs = [NSString:AnyObject]()
privateAttrs[kSecAttrIsPermanent] = true
privateAttrs[kSecAttrApplicationTag] = privateKeyTag
publicAttrs[kSecAttrIsPermanent] = true
publicAttrs[kSecAttrApplicationTag] = publicKeyTag
pairAttrs[kSecAttrKeyType] = kSecAttrKeyTypeRSA
pairAttrs[kSecAttrKeySizeInBits] = 2048
pairAttrs[(kSecPrivateKeyAttrs.takeUnretainedValue() as! String)] = privateAttrs
pairAttrs[(kSecPublicKeyAttrs.takeUnretainedValue() as! String)] = publicAttrs
var publicKeyPtr = Unmanaged<SecKey>?()
var privateKeyPtr = Unmanaged<SecKey>?()
let status = SecKeyGeneratePair(pairAttrs, &publicKeyPtr, &privateKeyPtr)
Note: publicKeyTag and privateKeyTag are strings used to identify the key in the keystore. Apple recommends reverse-dns notation (com.company.key.xxx), but as long as they are unique, all should be good.
Similar question with answer: Generate key pair on iphone and print to log as NSString
Although the answer there is in Objective-C, Apple reference shows that the functions (especially the most important one, SecKeyGeneratePair) can also be called directly from Swift (as long as you can do the type conversions from all those UnsafeMutablePointers etc).