RSA Encryption (softAP setup of microcontroller) in C# - javascript

I'm trying to configure wifi credentials for a particle photon (wifi microcontroller with cloud support).
There are existing methods for Java / ios / android / javascript.
However, i need to do this in C# (for a desktop and xamarin multiplatform app).
I succesfully managed to connect to the device, retreive it's ID, retreive the public key and the nearby wifi access points (using Webrequests and deserialized json objects)
However, i am stuck with the RSA encryption of the wifi password i need to pass through.
I'm trying to use the RSACryptoServiceProvider but to encrypt i need to pass a xml string and probably the key in a different (base64?) format. Also there seems to be some kind of splicing that needs to happen.
This is the retreived public key (in HEX):
30819F300D06092A864886F70D010101050003818D00308189028181009885DC94E34A23A2942BB9EB6721C4233E9EDCC9A967F587CEA527E1D447F48319CA6C4178DFF739C0AB079E02467DD4D3AD3214416F0983C3967EA71378D7D93A885F1575D71D009990BFFC0882FC721F4DC98A0D80B4CCF12E51066D69055E9A3C95E247BEB9DC16176A083DE7FA93C23449A3870D599DA9D507964F7FC4B90203010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
This is a function in github softap-js:
SoftAP.prototype.publicKey = function publicKey(cb) {
is(cb);
var sock = this.__sendCommand('public-key', response.bind(this));
function response(err, dat) {
if(err) { return cb(err); }
if(!dat) { return cb(new Error('No data received')); }
if(dat.r !== 0) {
return cb(new Error('Received non-zero response code'));
}
var buff = new Buffer(dat.b, 'hex');
this.__publicKey = new rsa(buff.slice(22), 'pkcs1-public-der', {
encryptionScheme: 'pkcs1'
})
cb(null, this.__publicKey.exportKey('pkcs8-public'));
};
return sock;
};
Which appears to handle the public key. i guess i just need to somehow convert this to .net but i would appreciate any help or hint with that since I'm not familiar at all with encryption.

Related

Decoding a device payload sent to the Helium Console

So I have defined an integration in the Helium Console (i.e. - an IoT LoRaWAN networking service). When I test out sending data from my IoT device to my Helium Console integration endpoint, I can see the payload. And I can manually decode it back to the JSON request body that's correct. But am having trouble defining a custom function in the Helium Console that will automate this for the integration. My IoT device is serializing a MsgPack payload of environmental data that's then sent to the Helium Console integration endpoint. And the Helium Console custom function allows Javascript, although just bare-bones without any requires, imports, etc.
Below is the Python script that can manually decode the payload. If anyone is familiar with this area I'd be interested as to suggestions. There are pre-defined decoders available for Helium, although none that match exactly my hardware.
If anyone has created custom decoding functions for Helium Console integrations I'd be curious as to how I could knock this out. Here is some info about this --> https://docs.helium.com/use-the-network/console/functions/.
import ssl, sys, json, base64
import msgpack
payload = "haJiVspAozMzo3RfQxilZWNfbVMWonBoB6NvcnAC"
# decode the payload from base64 and unpack
b64 = base64.b64decode(payload)
mp_dict = msgpack.unpackb(b64)
print(mp_dict) # output is {'bV': 5.099999904632568, 't_C': 24, 'orp': 2, 'ph': 7, 'ec_mS': 22}
Rather than reinvent the wheel, I modified the Arduino code running on my device. Pulling in the CayenneLPP library I manually encode what I need, so that the Helium Console's canned CayenneLPP decoding function can correctly parse the data.
Arduino code snippet below.
#include <CayenneLPP.h>
...
/*CayenneLPP variable*/
CayenneLPP lpp(51);
...
static void prepareTxFrame( uint8_t port )
{
appDataSize = lpp.getSize();
uint8_t lppBuffer[128];
memcpy(lppBuffer, lpp.getBuffer(), 128);
memcpy(appData, lppBuffer, lpp.getSize());
}
...
// The loop function is called in an endless loop
void loop()
{
lpp.reset();
lpp.addTemperature(1, 22.5);
lpp.addBarometricPressure(2, 1073.21);
lpp.addGPS(3, 52.37365, 4.88650, 2);
...
LoRaWAN.displaySending();
prepareTxFrame( appPort );
LoRaWAN.send(loraWanClass);
...
}
https://github.com/helium/console-decoders/blob/master/debugDecodeBase64.js
// LoRaWan devices automatically base64 encode data sent
// Sometimes nice just to view what original payload was sent
//
// This can help when writing your own decoder
//
//
function Decoder(bytes, port, uplink_info) {
var decoded={};
try{
var result = String.fromCharCode.apply(null, bytes);
decoded.value = result;
return decoded;
} catch (err) {
return 'Decoder: ' + err.name + " : " + err.message;;
}
}
// And in the integration section of the Helium console use this JSON
// For an Adafruit.io integration which is expecting JSON like { "value" : "56" }
//
// { "value": {{decoded.payload.value}} }
Create account on https://app.datacake.de/
Create integration to Datacake in here: https://console.helium.com/integrations
integrations
Link the flow in here:
https://console.helium.com/flows
flows
Create project and add device to DataCake, as decoder function use modified above (as is - it will receive a string)

AES Encryption/Decryption in Node JS similar to Java

I am trying to replicate the Java code for AES Encryption and Decryption in Node JS.
Java Code
SecretKeySpec skeySpec;
String key = "a4e1112f45e84f785358bb86ba750f48";
public void encryptString(String key) throws Exception {
try {
skeySpec = new SecretKeySpec(key.getBytes(), "AES");
cipher = Cipher.getInstance("AES");
cipher.init(1, skeySpec);
byte encstr[] = cipher.doFinal(message.getBytes());
String encData = new String(encstr, "UTF-8");
System.out.println(encData);
} catch (NoSuchAlgorithmException nsae) {
throw new Exception("Invalid Java Version");
} catch (NoSuchPaddingException nse) {
throw new Exception("Invalid Key");
}
}
Node JS
var encryptKey = function (text) {
var cipher = crypto.createCipher('aes256', 'a4e1112f45e84f785358bb86ba750f48');
var crypted = cipher.update(text,'utf8', 'hex')
crypted += cipher.final('hex');
console.log(crypted);
return crypted;
}
I am unable to get the exact cipher-text in Node JS, which i am getting in Java.
Your code actually uses different encryption parameters in the 2 cases. AES, being a block cipher, takes: the plain text to encrypt, the initialization vector, also called IV (which is used in conjunction with the plaintext), and the encryption key.
In Java, the IV is, apparently, generated automatically on init() - from the Java SE platform docs for Cipher.init:
The generated parameters can be retrieved using getParameters or getIV
(if the parameter is an IV).
In Node.js, if using the deprecated createCipher function, the IV is generated automatically based on the provided key, probably in a different way than in Java, so you will get a different cipher text. However, you should be using the non-deprecated variant crypto.createCipheriv: https://nodejs.org/docs/latest-v12.x/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options
In order to exactly reproduce the cipher text, you should:
Use the same encryption algorithm on both sides - it's best to specify this exactly, for example aes-256-cbc, or an authenticated encryption scheme such as aes-256-gcm, which is harder to use but provides message authentication.
Use the same IV on both sides, by providing it in the initialization params in Java, and by using createCipheriv in Node; though beware, you should always randomize it in production! See https://stackoverflow.com/a/20888967/6098312
As a closing remark, when using block encryption, you'll usually be generating securely-random IVs, which means the ciphertexts will always differ from one another, even for the same plaintext. This is a good thing! It protects your payload from an attacker who observes the encrypted data and makes conclusions based on message repetitions.
Finally after reviewing Java Docs and Node JS Crypto Docs managed to get the result.
We have to use crypto.createCipheriv() instead of crypto.createCipher with a iv.
Here iv will be null.
Code :
let crypto = require('crypto');
var iv = new Buffer.from(''); //(null) iv
var algorithm = 'aes-256-ecb';
var password = 'a4e1112f45e84f785358bb86ba750f48'; //key password for cryptography
function encrypt(buffer){
var cipher = crypto.createCipheriv(algorithm,new Buffer(password),iv)
var crypted = Buffer.concat([cipher.update(buffer),cipher.final()]);
return crypted;
}
console.log(encrypt(new Buffer('TextToEncrypt')).toString())

Download XML file with JavaScript and C#/Rest

I have an xml document that I generated in C#, I would like to return the string/document via WCF/REST so it will be downloaded by the browser. What is the operationcontract/return type that I should use? And how can I get it to be prompted to save by javascript and the browser.
Your operation contract should not be one way and you should return Stream
[OperationContract(IsOneWay = false)]
[WebGet(UriTemplate = "GetXml/{xmlFileName}")]
Stream GetXml(string xmlFileName);
public Stream GetXml(string xmlFileName)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream";
string xmlLocation=GetXmlLocation(xmlFileName);
try
{
return File.OpenRead(xmlLocation);
}
catch
{
// File Not Found
return null;
}
}
I had the similar issue with NodeJS backend.
I returned XML as a string and then on front-end I used next code:
Download

How do I decode a BASE64, PCKS-8 representation of a private key in NetSuite or javascript?

I'm working on a suitescript to integrate NetSuite with the Walmart Marketplace APIs. And, as the another OP here says it right their documentation pretty much says if you don't use Java you're on your own.
I'm looking for a way to do the same either in suitescript or javascript.
Instruction from Walmart's API documentation:
Sign the byte array representation of this data by:
Decoding the Base 64, PKCS-8 representation of your private key. Note that the key is encoded using PKCS-8. Libraries in various languages offer the ability to specify that the key is in this format and not in other conflicting formats such as PKCS-1. Use this byte representation of your key to sign the data using SHA-256 With RSA. Encode the resulting signature using Base 64.
And, a java code from their documentation to do the same:
public static String signData(String stringToBeSigned, String encodedPrivateKey) {
String signatureString = null;
try {
byte[] encodedKeyBytes = Base64.decodeBase64(encodedPrivateKey);
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(encodedKeyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey myPrivateKey = kf.generatePrivate(privSpec);
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(myPrivateKey);
byte[] data = stringToBeSigned.getBytes("UTF-8");
signature.update(data);
byte[] signedBytes = signature.sign();
signatureString = Base64.encodeBase64String(signedBytes);
} catch (Exception e) {
e.printStackTrace();
}
return signatureString;
}
For reference, here's the similar thing asked for dot net. Any help would be appreciated.
I tried developing a SAML connector in Javascript once and found several libraries that deal with different key file formats etc. I got fairly far along but the time to run some of the scripts was incredible (imagine trying to login but the process taking two minutes to decide your login was valid)
At that point I switched to an external system and managed the SSO with Netsuite's inbound SSO.
It doesn't look like things have improved that much with NS in the crypto department even with SS 2.0.
I'd tend to package this into two parts. Generate your files in Suitescript and pass them through a java based web service that handles the signing requirements. Minimizes the amount of Java you have to write and keeps your transaction extraction/formatting scripts under easy control.
I found a library (jsrsasign) that will do the Walmart signature from NetSuite server side in under 4 seconds! (Marketplace has gone to OAuth2, but I'm stuck with signing as a Drop Ship Vendor)
/**
*#NApiVersion 2.x
*#NScriptType ScheduledScript
*/
define(['N/log', 'N/https', '../lib/jsrsasign-master/jsrsasign-all-min'],
function(log, https) {
function execute(context) {
var pkcs8Der = {Your Walmart Private Key};
var pkcs8Pem = [
'-----BEGIN PRIVATE KEY-----',
pkcs8Der.match(/.{0,64}/g).join('\n'),
'-----END PRIVATE KEY-----'
].join('\n');
var tStamp = Date.now()
var stringToSign = [
tStamp,
{Your Walmart Comsumer Id},
{Request URL},
{Request Method (All Caps)}
].join('\n') + '\n';
var sig = new KJUR.crypto.Signature({"alg": "SHA256withRSA"});
sig.init(pkcs8Pem);
var sigVal = hextob64(sig.signString(stringToSign));
log.audit({title: 'Signature', details: sigVal});
log.audit({title: 'Timestamp', details: tStamp});
}
return {
execute: execute,
};
}
);
I had to add the following code to the jsrsasign-all-min.js library file for the Scheduled Script to load the module:
var navigator = {}, window = undefined;

Send Base64 encoded image as string to Chromecast

The problem is to send local image from phone as encoded Base64 string to Chromecast. And decode it using my Custom Receiver. I was following this guide which is based on this project sample.
I suggest the problem might be in:
Custom Receiver is not proper (I'm not strong in JS).
Chromecast didn't load that Receiver (I don't know how to check that).
Image was encoded wrong on device or decoded on Chromecast.
You see, it seems like I coded everithing right since the status of Chromecast when I send photo is:
statusCode 0 (success),
application name: Default Media Receiver,
status: Ready To Cast,
sessionId: 34D6CE75-4798-4294-BF45-2F4701CE4782,
wasLaunched: true.
This is how I send image as String:
mCastManager.castImage(mCastManager.getEncodedImage(currentEntryPictureByPoint.getPath()));
Methods used:
public void castImage(String encodedImage)
{
Log.d(TAG, "castImage()");
String image_string = createJsonMessage(MessageType.image, encodedImage);
sendMessage(image_string);
}
private static String createJsonMessage(MessageType type, String message)
{
return String.format("{\"type\":\"%s\", \"data\":\"%s\"}", type.toString(), message);
}
/**
* Convert Image to encoded String
* */
public String getEncodedImage(String path){
Bitmap bm = BitmapFactory.decodeFile(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] byteArrayImage = baos.toByteArray();
String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
return encodedImage;
}
/**
* Send a text message to the receiver
*
* #param message
*/
private void sendMessage(String message) {
if (mApiClient != null && mCustomImageChannel != null) {
try {
Cast.CastApi.sendMessage(mApiClient,
mCustomImageChannel.getNamespace(), message)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status result) {
if (!result.isSuccess()) {
//ALWAYS REACHING HERE :(
Log.e(TAG, "Sending message failed");
}
}
});
} catch (Exception e) {
Log.e(TAG, "Exception while sending message", e);
}
} else {
Toast.makeText(mContext, message, Toast.LENGTH_SHORT)
.show();
}
}
If the sending process is correct then the Receiver is wrong and don't know how to decode this message properly.
The way I uploaded it (well, at least I think that its uploaded...)
Registered new Custom Receiver on Google Cast Console and received Application ID.
Created cast_receiver.js file. The code inside this file is supposed to decode Base64 string into image.
Copied the code for Receiver from guide to .js file and changed NAMESPACE inside to my one: urn:x-cast:com.it.innovations.smartbus
Uploaded file on Google Drive and modified its access visibility to full public
Copied the link to file to URL field in Cast Console. This link is direct download of file.
Restarted Chromecast. Seems like it tried to download something but not sure if succeed
If anyone faced this problem, please point me out what I am doing wrong. Appreciate any help.
P.S. tell if some more code needed...
I very strongly suggest to avoid using the sendMessage() for sending any large data set; those channels are meant to be used as control channels and not as a way to send a chunk of data. A much much simpler and more robust approach is to embed a tiny dumb web server in your local app (on the sender side) and "serve" your images to your chromecast. There is a number of ready-to-use embedded web servers that you can put in your app and requires almost no configuration; then you can serve all sorts of media, including images, to your chromecast with even the default or styled receiver.

Categories

Resources