Equivalent of CBCBlockCipherMac from bouncycastle for swift - ios

I need to re-implement for iOS (swift) a cryptographic operation done for an Android app (kotlin) thanks to bouncycastle's lbrary.
The kotlin code is :
val mac = "9D3391051A4E774B".hexStringToByteArray()
val macKey = "89D7B23D500D492FA01DC53B44864AB8".hexStringToByteArray()
val cipheredData = "E77A914D5C94A04B6D8E10BA7A56A015AC2C40167F867A97B6349F29F3100D6D".hexStringToByteArray()
var macBlock = CBCBlockCipherMac(AESEngine(), ISO7816d4Padding())
macBlock.init(KeyParameter(macKey))
macBlock.update(cipheredData, 0, cipheredData.size)
var output = ByteArray(8)
macBlock.doFinal(output, 0)
if(output.toHex() == mac.toHex()) {
print("equals !!")
} else {
print("not equals : ${output.toHex()}")
}
This code works, the found mac from the output is the same as the original 'mac' property.
I tried using swift Library CryptoSwift with this code :
let mac = Data(hex: "9D3391051A4E774B")
let macKey = Data(hex: "89D7B23D500D492FA01DC53B44864AB8")
let cipheredData = Data(hex: "E77A914D5C94A04B6D8E10BA7A56A015AC2C40167F867A97B6349F29F3100D6D")
do {
var output = try CBCMAC(key: macKey.bytes).authenticate(cipheredData.bytes)
checkOutput(mac: mac, output: output)
} catch {
debugPrint("Exception \(error)")
}
But this doesn't work. The algorithm behind the CryptoSwift's CBCMAC class is not doing the same think as bouncycastle's CBCBlockCipherMac.
I also tried using apple's CommonCrypto library but there is no CBCMAC authentification, only HMAC. I didn't find any way of doing CBC-MAC authentification easily for iOS plateform.

I found a solution, developing the real CBC-MAC encryption in CryptoSwift class :
public func authenticate(_ cipheredBytes: Array<UInt8>, padding: Padding, blockSize: Int) throws -> Array<UInt8> {
var inBytes = cipheredBytes
bitPadding(to: &inBytes, blockSize: blockSize)
let blocks = inBytes.chunked(into: blockSize)
var lastBlockEncryptionResult : [UInt8] = CBCMAC.Zero
try blocks.forEach { (block) in
let aes = try AES(key: Array(key), blockMode: CBC(iv: lastBlockEncryptionResult), padding: padding)
lastBlockEncryptionResult = try aes.encrypt(block)
}
return lastBlockEncryptionResult
}
Calling this with my initial parameters gives the answer :
9d3391051a4e774b7572fb9bca51dc51
So the first 8 bits are the good ones.

Related

Deprecated withUnsafeBytes [duplicate]

I previously used this code in Swift 4.2 to generate an id:
public static func generateId() throws -> UInt32 {
let data: Data = try random(bytes: 4)
let value: UInt32 = data.withUnsafeBytes { $0.pointee } // deprecated warning!
return value // + some other stuff
}
withUnsafeBytes is deprecated on Swift 5.0. How can I solve this?
In Swift 5 the withUnsafeBytes() method of Data calls the closure with an (untyped) UnsafeRawBufferPointer, and you can load() the value from the raw memory:
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
(compare How to use Data.withUnsafeBytes in a well-defined manner? in the Swift forum). Note that this requires that the memory is aligned on a 4-byte boundary. For alternatives see round trip Swift number types to/from Data.
Note also that as of Swift 4.2 you can create a random 32-bit integer simply using the new Random API:
let randomId = UInt32.random(in: .min ... .max)
On Xcode 10.2, Swift 5, using $0.load(as:) didn't work for me, both when reading from the pointer or writing to it.
Instead, using $0.baseAddress?.assumingMemoryBound(to:) seems to work well.
Example reading from the pointer buffer (code is unrelated to the question):
var reachability: SCNetworkReachability?
data.withUnsafeBytes { ptr in
guard let bytes = ptr.baseAddress?.assumingMemoryBound(to: Int8.self) else {
return
}
reachability = SCNetworkReachabilityCreateWithName(nil, bytes)
}
Example writing to the buffer pointer (code is unrelated to the question):
try outputData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) in
let status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
passphrase,
passphrase.utf8.count,
salt,
salt.utf8.count,
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1),
rounds,
outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
kCCKeySizeAES256)
guard status == kCCSuccess else {
throw Error.keyDerivationError
}
}
The code from the question would look like:
let value = data.withUnsafeBytes {
$0.baseAddress?.assumingMemoryBound(to: UInt32.self)
}
In cases where the 'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(…) warning persists, it seems like the compiler can get confused when the closure has only one line. Making the closure have two or more lines might remove the ambiguity.
One more way to fix this warning to use bindMemory(to:).
var rawKey = Data(count: rawKeyLength)
let status = rawKey.withUnsafeMutableBytes { rawBytes -> Int32 in
guard let rawBytes = rawBytes.bindMemory(to: UInt8.self).baseAddress else {
return Int32(kCCMemoryFailure)
}
return CCSymmetricKeyUnwrap(alg, ivBytes, iv.count, keyBytes, key.count, wrappedKeyBytes, wrappedKey.count, rawBytes, &rawKeyLength)
}
I got this error as I was trying to figure out a compression stream tutorial. To get it to work, I added a step of converting the raw buffer pointer to a UnsafePointer
Original code from a tutorial I was working on.
--> where input: Data
--> where stream: compression_stream
//Method that shows the deprecation alert
return input.withUnsafeBytes { (srcPointer: UnsafePointer<UInt8>) in
//holder
var output = Data()
//Source and destination buffers
stream.src_ptr = srcPointer //UnsafePointer<UInt8>
stream.src_size = input.count
… etc.
}
Code with a conversion to make the above code work with a valid method
return input.withUnsafeBytes { bufferPtr in
//holder
var output = Data()
//Get the Raw pointer at the initial position of the UnsafeRawBuffer
let base: UnsafeRawPointer? = bufferPtr.baseAddress
//Unwrap (Can be combined with above, but kept it separate for clarity)
guard let srcPointer = base else {
return output
}
//Bind the memory to the type
let count = bufferPtr.count
let typedPointer: UnsafePointer<UInt8> = srcPointer.bindMemory(to: UInt8.self, capacity: count)
// Jump back into the original method
stream.src_ptr = typedPointer //UnsafePointer<UInt8>
}

How to invoke device method in ios using azure iot sdk

I am trying to call a method associated with the device using connection string.
I tried with the samples provided with other languages I am able to call the method in the device. eg: "setState" or "getState" of the lamp.
But I am not able to implement in iOS using swift.
I tried to match parameter parameter requirement by referring to the C sample. But I am getting
1. Func:sendHttpRequestDeviceMethod Line:337 Http Failure status code 400.
2. Func:IoTHubDeviceMethod_Invoke Line:492 Failure sending HTTP request for device method invoke
var status :Int32! = 0
var deviceId = "simulated_device_one";
var methodName = "GetState";
var uint8Pointer:UnsafeMutablePointer<UInt8>!
uint8Pointer = UnsafeMutablePointer<UInt8>.allocate(capacity:8)
var size = size_t(10000)
var bytes: [UInt8] = [39, 77, 111, 111, 102, 33, 39, 0]
uint8Pointer?.initialize(from: &bytes, count: 8)
var intValue : UnsafeMutablePointer<UInt8>?
intValue = UnsafeMutablePointer(uint8Pointer)
var char: UInt8 = UInt8(20)
var charPointer = UnsafeMutablePointer<UInt8>(&char)
var prediction = intValue
let serviceClientDeviceMethodHandle = IoTHubDeviceMethod_Create(service_client_handle)
let payLoad = "test"
var responsePayload = ""
let invoke = IoTHubDeviceMethod_Invoke(serviceClientDeviceMethodHandle, deviceId, methodName, payLoad , 100, &status, &prediction,&size )
I want to call a method in the device using IoTHubDeviceMethod_Invoke
You can download View controller file which I worked on from here
1.Create Connection in view did load
// declaring your connection string you can find it in azure iot dashboard
private let connectionString = "Enter your connection String";
// creating service handler
private var service_client_handle: IOTHUB_SERVICE_CLIENT_AUTH_HANDLE!;
// handler for the method invoke
private var iot_device_method_handle:IOTHUB_SERVICE_CLIENT_DEVICE_METHOD_HANDLE!;
// In view did load establish the connection
service_client_handle = IoTHubServiceClientAuth_CreateFromConnectionString(connectionString)
if (service_client_handle == nil) {
showError(message: "Failed to create IoT Service handle", sendState: false)
}
create method invoke function
I created it based on the demo provided for sending message
func openIothubMethodInvoke() -> Bool
{
print("In openIotHub method invoke")
let result: Bool;
iot_device_method_handle = IoTHubDeviceMethod_Create(service_client_handle);
let testValue : Any? = iot_device_method_handle;
if (testValue == nil) {
showError(message: "Failed to create IoT devicemethod", sendState: false);
result = false;
}
else
{
result = true;
}
return result;
}
call method invoke
** this is the main function for calling the method
func methodInvoke()
{
let testValue : Any? = iot_device_method_handle;
if (testValue == nil && !openIothubMethodInvoke() ) {
print("Failued to open IoThub messaging");
}
else {
let size = UnsafeMutablePointer<Int>.allocate(capacity: 1)
let responseStatus = UnsafeMutablePointer<Int32>.allocate(capacity: 1)
// Payload is the main change it is like specifying the format
var payload = UnsafeMutablePointer<UnsafeMutablePointer<UInt8>?>.allocate(capacity: 1)
// if payload is not expected please send empty json "{}"
let result = IoTHubDeviceMethod_Invoke(iot_device_method_handle, "nameOfTheDeviceYouWantToCallOn", "MethodName", "{payload you want to send}", 100, responseStatus, payload , size)
// extracting the data from response
let b = UnsafeMutableBufferPointer(start: payload.pointee, count: size.pointee)
let data = Data(buffer: b)
let str = String(bytes: data, encoding: .utf8)
print(str)
do{
let value = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(value)
}catch{
print(error)
}
}
}
As discussed above: the payload needs to be valid JSON. Even an empty json will do such as {}

How is a CoreMIDI Thru Connection made in swift 4.2?

The following builds and runs and prints the non error console message at the end when passed two valid MIDIEndPointRefs. But midi events are not passed thru from source to dest as expected. Is something missing?
func createThru2(source:MIDIEndpointRef?, dest:MIDIEndpointRef?) {
var connectionRef = MIDIThruConnectionRef()
var params = MIDIThruConnectionParams()
MIDIThruConnectionParamsInitialize(&params)
if let s = source {
let thruEnd = MIDIThruConnectionEndpoint(endpointRef: s, uniqueID: MIDIUniqueID(1))
params.sources.0 = thruEnd
params.numSources = 1
print("thru source is \(s)")
}
if let d = dest {
let thruEnd = MIDIThruConnectionEndpoint(endpointRef: d, uniqueID: MIDIUniqueID(2))
params.destinations.0 = thruEnd
params.numDestinations = 1
print("thru dest is \(d)")
}
var localParams = params
let nsdata = withUnsafePointer(to: &params) { p in
NSData(bytes: p, length: MIDIThruConnectionParamsSize(&localParams))
}
let status = MIDIThruConnectionCreate(nil, nsdata, &connectionRef)
if status == noErr {
print("created thru")
} else {
print("error creating thru \(status)")
}
}
Your code works fine in Swift 5 on macOS 10.13.6. A thru connection is established and MIDI events are passed from source to destination. So the problem does not seem to be the function you posted, but in the endpoints you provided or in using Swift 4.2.
I used the following code to call your function:
var source:MIDIEndpointRef = MIDIGetSource(5)
var dest:MIDIEndpointRef = MIDIGetDestination(9)
createThru2(source:source, dest:dest)
5 is a MIDI keyboard and 9 is a MIDI port on my audio interface.
Hmmm. I just tested this same code on Swift 5 and OS X 12.4, and it doesn't seem to work for me. MIDIThruConnectionCreate returns noErr, but no MIDI packets seem to flow.
I'm using the MIDIKeys virtual source, and MIDI Monitor virtual destination.
I'll try it with some hardware and see what happens.

Use JS library in Flutter

I am trying to use Ether JS in my Flutter application. I know that it is not directly supported and even the existing implementations are not really well documented.
Is there any way I can use this library in my Flutter application for Android and iOS? Any other alternative suggestion is also welcome.
I have tried js.dart but could not figure out how to use it. I am not even sure if it is the right choice for this scenario.
I have also tried Flutter WebView Plugin.
plugin.evalJavascript(
'function add(a,b){return a+b;}add(2,3);'
).then((s) {
print(s);
}
This function rightly returns 5 as the response. But I do not understand how to use the EtherJS library like this.
I am a noob with Flutter, Dart and JS. Any help will be appreciated.
I eventually solved this by using Platform channels as suggested by rmtmckenzie in this answer.
I downloaded the JS file and saved it to android/app/src/main/res/raw/ether.js and ios/runner/ether.js for Android and iOS respectively.
Installing dependencies
Android
Add LiquidCore as a dependency in app level build.gradle
implementation 'com.github.LiquidPlayer:LiquidCore:0.5.0'
iOS
For iOS I used the JavaScriptCore which is part of the SDK.
Platform Channel
In my case, I needed to create a Wallet based on a Mnemonic (look up BIP39) I pass in into the JS function. For this, I created a Platform channel which passes in the Mnemonic (which is basically of type String) as an argument and will return a JSON object when done.
Future<dynamic> getWalletFromMnemonic({#required String mnemonic}) {
return platform.invokeMethod('getWalletFromMnemonic', [mnemonic]);
}
Android Implementation (Java)
Inside MainActivity.java add this after this line
GeneratedPluginRegistrant.registerWith(this);
String CHANNEL = "UNIQUE_CHANNEL_NAME";
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
#Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("getWalletFromMnemonic")) {
ArrayList<Object> args = (ArrayList<Object>) methodCall.arguments;
String mnemonic = (String) args.get(0);
JSObject walletFromMnemonic = getWalletFromMnemonic(mnemonic);
if (walletFromMnemonic == null) {
result.error("Could not create", "Wallet generation failed", null);
return;
}
String privateKey = walletFromMnemonic.property("privateKey").toString();
String address = walletFromMnemonic.property("address").toString();
HashMap<String, String> map = new HashMap<>();
map.put("privateKey", privateKey);
map.put("address", address);
JSONObject obj = new JSONObject(map);
result.success(obj.toString());
} else {
result.notImplemented();
}
}
}
);
Declare the following methods which perform the actual action of interacting with the JS library and returning the result to the platform channel.
#Nullable
#VisibleForTesting
private JSObject getWalletFromMnemonic(String mnemonic) {
JSContext jsContext = getJsContext(getEther());
JSObject wallet = getWalletObject(jsContext);
if (wallet == null) {
return null;
}
if (!wallet.hasProperty("fromMnemonic")) {
return null;
}
JSFunction walletFunction = wallet.property("fromMnemonic").toObject().toFunction();
return walletFunction.call(null, mnemonic).toObject();
}
#Nullable
#VisibleForTesting
private JSObject getWalletObject(JSContext context) {
JSObject jsEthers = context.property("ethers").toObject();
if (jsEthers.hasProperty("Wallet")) {
return jsEthers.property("Wallet").toObject();
}
return null;
}
#VisibleForTesting
String getEther() {
String s = "";
InputStream is = getResources().openRawResource(R.raw.ether);
try {
s = IOUtils.toString(is);
} catch (IOException e) {
s = null;
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
}
return s;
}
#VisibleForTesting
JSContext getJsContext(String code) {
JSContext context = new JSContext();
context.evaluateScript(code);
return context;
}
iOS Implementation (Swift)
Add the following lines in AppDelegate.swift inside the override application method.
final let methodChannelName: String = "UNIQUE_CHANNEL_NAME"
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel.init(name: methodChannelName, binaryMessenger: controller)
methodChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: FlutterResult)-> Void in
if call.method == "getWalletFromMnemonic" {
guard let mnemonic = call.arguments as? [String] else {
return
}
if let wallet = self.getWalletFromMnemonic(mnemonic: mnemonic[0]) {
result(wallet)
} else {
result("Invalid")
}
}
})
Add the logic to interact with the JavaScriptCore.
private func getWalletFromMnemonic(mnemonic: String) -> Dictionary<String, String>? {
let PRIVATE_KEY = "privateKey"
let ADDRESS = "address"
guard let jsContext = self.initialiseJS(jsFileName: "ether") else { return nil }
guard let etherObject = jsContext.objectForKeyedSubscript("ethers") else { return nil }
guard let walletObject = etherObject.objectForKeyedSubscript("Wallet") else { return nil }
guard let walletFromMnemonicObject = walletObject.objectForKeyedSubscript("fromMnemonic") else {
return nil
}
guard let wallet = walletFromMnemonicObject.call(withArguments: [mnemonic]) else { return nil }
guard let privateKey = wallet.forProperty(PRIVATE_KEY)?.toString() else { return nil }
guard let address = wallet.forProperty(ADDRESS)?.toString() else { return nil }
var walletDictionary = Dictionary<String, String>()
walletDictionary[ADDRESS] = address
walletDictionary[PRIVATE_KEY] = privateKey
return walletDictionary
}
private func initialiseJS(jsFileName: String) -> JSContext? {
let jsContext = JSContext()
guard let jsSourcePath = Bundle.main.path(forResource: jsFileName, ofType: "js") else {
return nil
}
do {
let jsSourceContents = try String(contentsOfFile: jsSourcePath)
jsContext!.evaluateScript(jsSourceContents)
return jsContext!
} catch {
print(error.localizedDescription)
}
return nil
}
Honestly, if you're new to Flutter, Dart, and JS you are going to have some trouble with this unless you're willing to invest a fair amount of time. It does depend on what exactly you're trying to make with the Ether JS library, but in general you're going to have a hard time integrating it with flutter. There is an Ethereum package but it seems much narrower in scope than the ether.js library you've been looking at - it mostly seems focused on communication with the RPC api rather than dealing with wallets etc.
If you're dead set on using Flutter, your best bet would be to use Android & iOS specific libraries to do the actual ethereum stuff and to communicate through Platform Channels to a common api in your dart code. This could be a significant undertaking depending on how much of the API you need to expose, especially for someone new to flutter/dart and possibly to android/ios development as well. This will be much more performant than communicating back and forth with javascript running in a webview though, and realistically probably easier to code as well because flutter doesn't really have any good mechanisms for calling js code right now.
There is another option - to use a different client UI framework entirely. React native might do everything you need and has the advantage of being in Javascript so it can most likely integrate the Ether.js library easily, although I can't guarantee that it will actually fully support the ether.js library (its runtime might not have the necessary crypto extensions for example).
Future<String> loadJS(String name) async {
var givenJS = rootBundle.loadString('assets/$name.js');
return givenJS.then((String js) {
flutterWebViewPlugin.onStateChanged.listen((viewState) async {
if (viewState.type == WebViewState.finishLoad) {
flutterWebViewPlugin.evalJavascript(js);
}
});
});
}

rac_textSignal in Swift 3

I am attempting to migrate a Swift 2.2 app that I did not write to Swift 3. All was going well until I ran into some RAC calls. I am not familiar with ReactiveCocoa, which makes this even more challenging.
/**
* Method name: Enable Login Button
* Description: Enable or disable login button based on
* username and password entry
* Parameters: None
*/
func enableLoginButton() -> Void {
self.btnLogin.isEnabled = false
let serviceUrlSignal = self.txtServiceUrl.rac_textSignal()
.toSignalAssumingHot()
.assumeNoErrors()
.map { text in text as! String }
let usernameSignal = self.txtFieldUsername.rac_textSignal()
.toSignalAssumingHot()
.assumeNoErrors()
.map { text in text as! String }
let userNameCharSignal = usernameSignal.map { $0.characters.count }
let passwordSignal = self.txtFieldPassword.rac_textSignal()
.toSignalAssumingHot()
.assumeNoErrors()
.map { text in text as! String }
let passwordCharSignal = passwordSignal.map { $0.characters.count }
userNameCharSignal.combineLatestWith(passwordCharSignal)
.map
{
charArray in charArray.0 > 0 && charArray.1 > 0
}
.observe { event in
if let buttonEnabled = event.value {
self.btnLogin.enabled = buttonEnabled
}
}
viewModel.username <~ usernameSignal
viewModel.password <~ passwordSignal
viewModel.serviceUrl <~ serviceUrlSignal
btnLogin.rac_signalForControlEvents(.TouchUpInside)
.subscribeNext{
button in
print("Authenticate Click!")
}
}
From what I understand, rac_textSignal does not exist in ReactiveSwift. Do I need to install ReactiveObjC or is there a Swift approach that I could use to replace this functionality? Thanks.
You'll need to add ReactiveCocoa in addition to ReactiveSwift.
Since the repo split, the core of what was ReactiveCocoa is now implemented in ReactiveSwift, but ReactiveCocoa adds Cocoa specific things like UIKit bindings which you'll need.
UIKit bindings are accessible via the reactive property, e.g. textfield.reactive.continuousTextValues.
Since these bindings are already correctly typed (as opposed to rac_textSignal), you can replace the whole chunk of
let usernameSignal = self.txtFieldUsername.rac_textSignal()
.toSignalAssumingHot()
.assumeNoErrors()
.map { text in text as! String }
...
viewModel.username <~ usernameSignal
with
viewModel.username <~ self.txtFieldUsername.reactive.continuousTextValues

Resources