智能音箱是目前熱火的智能產品,有很多家企業推出自己的智能音箱,並且進行了開放平台,允許第三方開發者,基於開放平台進行應用開發,豐富自己產品功能。
本人則購買一台 京東與訊飛合作的產品,叮咚智能音箱。並且在里面開發一個小應用“小軍找手機”,
但在開發過程中遇到一個坑,利用C#開發語言,實現叮咚開放平台 的加解密。因為叮咚平台是用JAVA加密,我主用C#語言。
平台在第三方應用中需要進行參數設置,見下圖,要求設置密鑰,即128個字符的字符串。因官方采用JAVA語言開發,如果第三方應用采用.NET 開發,則按頁面中的JAVA的方式無法正確解密回明文的state ,即json:{"userid":"用戶標識","operation":"oauth","timestamp":"時間戳,毫秒","appid":"應用的APPID"} 。這段字符串的反解。
經過群里伙伴的幫助,終於實現反解。現將教程公布如下:
再次感謝 群中 @SuperCokou @智家e物聯 @華仔愛技術
最重要的https://yq.aliyun.com/articles/2513 本頁的原創者 華仔愛技術

官方應用對state參數的解密過程
1.應用將接收到的數據進行Url解碼,state_base64 = UrlDecoder.decode(state,"UTF-8")
2.應用將解碼后到的數據進行Base64解碼 state_mi = Base64.decode(state_base64)
3.應用使用應用配置的AesKey秘鑰進行數據的解密 state = AES.decrypt(state_mi,AesKey)
應用.NET進行參數解密的過程
1.用附的JAVA代碼 見下,將代碼中key='12345578 中的變量key ,替換成你自己所用的回調地址參數秘鑰,即參數配置中的秘鑰。
2.在DOS環境,運行javac TestGenAESByteKey和java TestGenAESByteKey 然后得到類似這種的字符串 a0UcXq pLnhoWpzpHYcl1+A==
以上兩步,在第三方應用的代碼方法之外使用,因為一些底層加密的原因,具體的不作討論。
3.下面 C# 代碼 Decrypt方法 反解出 state。這部分在第三方應用中
附JAVA代碼:
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import sun.misc.BASE64Encoder;
public class TestGenAESByteKey{
/**
* @param args
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String key="12345678123456768123456781234567681234567812345676812345678123456768123456781234567681234567812345676812345678123456768123456781";
KeyGenerator kgen = KeyGenerator.getInstance("AES");
java.security.SecureRandom random = java.security.SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kgen.init(128, random);
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
BASE64Encoder coder = new BASE64Encoder();
System.out.println(coder.encode(enCodeFormat));
}
}
附C#代碼
/// <summary>
/// 服務開啟關閉回調
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
public ContentResult OpenService(string state)
{
string state_base64 = HttpUtility.UrlDecode(state,Encoding.UTF8);
String decrypt_state = Decrypt(state_base64);
///下面為具體的業務邏輯
}
private static string Decrypt(string toDecrypt)
{
byte[] keyArray = Convert.FromBase64String(@"a0UcbepLnhoWpzpHYcl1+A==");
byte[] inputBuffer = Convert.FromBase64String(toDecrypt);
RijndaelManaged rDel = new RijndaelManaged();
rDel.Key = keyArray;
rDel.Mode = CipherMode.ECB;
rDel.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = rDel.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
return Encoding.UTF8.GetString(resultArray);
}
[王老師玩ESP32系列]第十四課,ESP32使用RTOS之任務傳參
By 物物互動2017.9.30 10:44
/* structure that hold data*/
typedef struct{
int sender;
int counter;
}Data;
/* this variable hold queue handle */
xQueueHandle xQueue;
void setup() {
Serial.begin(112500);
/* create the queue which size can contains 5 elements of Data */
xQueue = xQueueCreate(5, sizeof(Data));
xTaskCreate(
sendTask1, /* Task function. */
"sendTask1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
2, /* priority of the task */
NULL); /* Task handle to keep track of created task */
xTaskCreate(
sendTask2, /* Task function. */
"sendTask2", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
2, /* priority of the task */
NULL); /* Task handle to keep track of created task */
xTaskCreate(
receiveTask, /* Task function. */
"receiveTask", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
1, /* priority of the task */
NULL); /* Task handle to keep track of created task */
}
void loop() {
}
void sendTask1( void * parameter )
{
/* keep the status of sending data */
BaseType_t xStatus;
/* time to block the task until the queue has free space */
const TickType_t xTicksToWait = pdMS_TO_TICKS(100);
/* create data to send */
Data data;
/* sender 1 has id is 1 */
data.sender = 1;
data.counter = 1;
for(;;){
Serial.println("sendTask1 is sending data");
/* send data to front of the queue */
xStatus = xQueueSendToFront( xQueue, &data, xTicksToWait );
/* check whether sending is ok or not */
if( xStatus == pdPASS ) {
/* increase counter of sender 1 */
data.counter = data.counter + 1;
}
/* we delay here so that receiveTask has chance to receive data */
delay(1000);
}
vTaskDelete( NULL );
}
/* this task is similar to sendTask1 */
void sendTask2( void * parameter )
{
BaseType_t xStatus;
const TickType_t xTicksToWait = pdMS_TO_TICKS(100);
Data data;
data.sender = 2;
data.counter = 1;
for(;;){
Serial.println("sendTask2 is sending data");
xStatus = xQueueSendToFront( xQueue, &data, xTicksToWait );
if( xStatus == pdPASS ) {
data.counter = data.counter + 1;
}
delay(1000);
}
vTaskDelete( NULL );
}
void receiveTask( void * parameter )
{
/* keep the status of receiving data */
BaseType_t xStatus;
/* time to block the task until data is available */
const TickType_t xTicksToWait = pdMS_TO_TICKS(100);
Data data;
for(;;){
/* receive data from the queue */
xStatus = xQueueReceive( xQueue, &data, xTicksToWait );
/* check whether receiving is ok or not */
if(xStatus == pdPASS){
/* print the data to terminal */
Serial.print("receiveTask got data: ");
Serial.print("sender = ");
Serial.print(data.sender);
Serial.print(" counter = ");
Serial.println(data.counter);
}
}
vTaskDelete( NULL );
}
