Безопасная связь между Arduino и PHP с использованием RC4 и base64
Я пытаюсь сделать слегка защищенную связь между Arduino и PHP. Я не могу использовать SSL из-за отсутствия питания на Arduino. Поэтому я хотел использовать RC4 для шифрования данных из PHP, а также получать в Arduino и расшифровывать. также зашифровать с Arduino и отправить на PHP.
Проблема в том, что зашифрованные данные, отправленные с PHP, не совпадают в Arduino.
На PHP я получаю HesshwkfFk8Q в base64, а в Arduino я получаю nZcwrlpZEr0V в base64. разные результаты, когда они должны быть равны.
Я думаю, что у меня неправильная реализация Arduino RC4. Я использую этот https://github.com/adamvr/arduino-base64
Это код:
Arduino
#include <Base64.h>
unsigned char S[256];
char has[512];
#define S_SWAP(a,b) do { int t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
void rc4(char *key, char *data){
int i,j;
for (i=0;i<256;i++){
S[i] = i;
}
j = 0;
for (i=0;i<256;i++){
j = (j+S[i]+key[i%strlen(key)]) %256;
S_SWAP(S[i],S[j]);
}
i = j = 0;
for (int k=0;k<strlen(data);k++){
i = (i+1) %256;
j = (j+S[i]) %256;
S_SWAP(S[i],S[j]);
has[k] = data[k]^S[(S[i]+S[j]) %256];
}
has[strlen(data)+1] = '\0';
}
void setup() {
Serial.begin(9600);
char key[] = "Hello";
char sdata[] = "secretMsg";
rc4(key,sdata);
Serial.print("Encrypted : ");
char out[100];
base64_encode(out,has,strlen(has));
Serial.println(out);
char out2[100];
base64_decode(out2,out,strlen(out));
rc4(key,out2);
Serial.print("Decrypted : ");
Serial.println(has);
}
void loop(){
}
PHP
<?php
$key = 'Hello';
$msg = 'secretMsg';
$encrypted = rc4_crypt($key, $msg);
echo 'encrypted b64: ', base64_encode($encrypted) ,'<br>';
echo "decrip: " , rc4_decrypt($key,rc4_crypt($key, $msg));
exit;
function rc4_crypt($key,$msg) {
$td = mcrypt_module_open('arcfour', '' , 'stream', '');
mcrypt_generic_init($td, $key, null);
$encrypted = mcrypt_generic($td, $msg);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypted;
}
function rc4_decrypt($key,$msg) {
return rc4_crypt($key,$msg);
}
?>
3 ответа
У меня была та же проблема, и я могу подтвердить, что ваша функция RC4 в Arduino неправильная, вы можете использовать это вместо:
unsigned char S[256];
unsigned int i, j;
void swap(unsigned char *s, unsigned int i, unsigned int j) {
unsigned char temp = s[i];
s[i] = s[j];
s[j] = temp;
}
/* KSA */
void rc4_init(unsigned char *key, unsigned int key_length) {
for (i = 0; i < 256; i++)
S[i] = i;
for (i = j = 0; i < 256; i++) {
j = (j + key[i % key_length] + S[i]) & 255;
swap(S, i, j);
}
i = j = 0;
}
/* PRGA */
unsigned char rc4_output() {
i = (i + 1) & 255;
j = (j + S[i]) & 255;
swap(S, i, j);
return S[(S[i] + S[j]) & 255];
}
Это текущая реализация, которую я использую
#define SWAP(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
class RC4
{
public:
RC4 ()
{
memset(sbox,0,256);
memset(key,0,256);
}
virtual ~RC4 ()
{
memset(sbox,0,256);
memset(key,0,256);
}
char *Encrypt(char *pszText,const char *pszKey)
{
i=0, j=0,n = 0;
ilen = (int)strlen(pszKey);
for (m = 0; m < 256; m++)
{
*(key + m)= *(pszKey + (m % ilen));
*(sbox + m) = m;
}
for (m=0; m < 256; m++)
{
n = (n + *(sbox+m) + *(key + m)) &0xff;
SWAP(*(sbox + m),*(sbox + n));
}
ilen = (int)strlen(pszText);
for (m = 0; m < ilen; m++)
{
i = (i + 1) &0xff;
j = (j + *(sbox + i)) &0xff;
SWAP(*(sbox+i),*(sbox + j));
k = *(sbox + ((*(sbox + i) + *(sbox + j)) &0xff ));
if(k == *(pszText + m))
k = 0;
*(pszText + m) ^= k;
}
return pszText;
}
char *Decrypt(char *pszText,const char *pszKey)
{
return Encrypt(pszText,pszKey) ;
}
private:
unsigned char sbox[256];
unsigned char key[256],k;
int m, n, i, j, ilen;
};
;
После множества безуспешных попыток я получил следующие три кода:
- Код Arduino реализовал RC4 (адаптированный из этого кода C++ ) и кодировал зашифрованный результат в Base64.
- Код PHP, который декодирует base64 и расшифровывает RC4
- HTML для тестирования PHP (и в конечном итоге это будет индекс веб-сервера ESP32)
На момент написания я использую ядро Arduino для ESP32 версии 2.0.0, учтите, что если вы не используете эту версию Base64.h, может быть несовместимость (подробнее здесь )
Код Arduino
#include "base64.h"
#include "rc4.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
void rc4_setup( struct rc4_state *s, unsigned char *key, int length )
{
int i, j, k, *m, a;
s->x = 0;
s->y = 0;
m = s->m;
for( i = 0; i < 256; i++ )
{
m[i] = i;
}
j = k = 0;
for( i = 0; i < 256; i++ )
{
a = m[i];
j = (unsigned char) ( j + a + key[k] );
m[i] = m[j]; m[j] = a;
if( ++k >= length ) k = 0;
}
}
void rc4_crypt( struct rc4_state *s, unsigned char *data, int length )
{
int i, x, y, *m, a, b;
x = s->x;
y = s->y;
m = s->m;
for( i = 0; i < length; i++ )
{
x = (unsigned char) ( x + 1 ); a = m[x];
y = (unsigned char) ( y + a );
m[x] = b = m[y];
m[y] = a;
data[i] ^= m[(unsigned char) ( a + b )];
}
s->x = x;
s->y = y;
}
int main()
{
char key[128] = {"Hello"};
char data[512] = {"secretMsg"};
struct rc4_state *s;
s=(struct rc4_state *) malloc (sizeof(struct rc4_state));
printf("key : %s\n", key);
printf("raw : %s\n", data);
rc4_setup(s, (unsigned char *)key, strlen(key));
/*
int i;
for (i = 0; i < 256; i++) {
printf("%d ", s->m[i]);
}
printf("\n");
*/
rc4_setup(s, (unsigned char *)key, strlen(key));
rc4_crypt(s, (unsigned char *)data, strlen(data));
printf("encrypt : %s\n",data);
base64 b;
String encoded = b.encode((unsigned char *)data, strlen(data));
Serial.println(encoded);
rc4_setup(s, (unsigned char *)key, strlen(key));
rc4_crypt(s, (unsigned char *)data, strlen(data));
printf("decrypt : %s\n",data);
return 0;
}
void setup(){
Serial.begin(115200);
main();
}
void loop(){
}
КОД PHP
<?php
function rc4_crypt($key,$msg) {
$td = mcrypt_module_open('arcfour', '' , 'stream', '');
mcrypt_generic_init($td, $key, null);
$encrypted = mcrypt_generic($td, $msg);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return $encrypted;
}
function rc4_decrypt($key,$msg) {
return rc4_crypt($key,$msg);
}
if(isset($_POST['base'])) {
$key = 'Hello';
$msg_revealed = $_POST['base'];
rc4_decrypt($key, base64_decode($msg_revealed)) //decode form base64 and decrypt
$msg = 'secretMsg'; //for testing
$encrypted = rc4_crypt($key, $msg);
echo 'encrypted b64: ', base64_encode($encrypted) ,'<br>';
echo "decrip: " , rc4_decrypt($key,rc4_crypt($key, $msg));
exit;
}
?>
HTML-КОД ДЛЯ ТЕСТИРОВАНИЯ и, в конечном итоге, код, который будет размещен на веб-сервере ESP32 (подробнее здесь )
<html >
<head>
<title>test Base64</title>
<meta http-equiv='content-type' content='text/html;charset=utf-8' />
<meta name='generator' content='Geany 1.36' />
</head>
<body>
<form action='https://www.yourwebsite.com/base64.php' method='post' id='downloadForm'>
<input hidden name='base' value='PASS_THE_BASE64_ENCRYPTED_STRING_HERE'>
</form>
<div style='text-align: center;'><button type='button' class='btn btn-danger' onclick='sendBaseForm()'>TEST</button></div>
</body>
<script>
function sendBaseForm(){
document.getElementById('downloadForm').submit();
}
</script>
</html>