4

我正在尝试在 Arduino 和 PHP 之间进行适度安全的通信。由于 Arduino 电源不足,我无法使用 SSL。所以我想使用 RC4 加密来自 PHP 的数据,然后接收到 Arduino 并解密。也从 Arduino 加密并发送到 PHP。

问题是从 PHP 发送的加密数据在 Arduino 中不重合。

在 PHP 上,我在 base64 中得到 HesshwkfFk8Q,在 Arduino 中,我在 base64 中得到 nZcwrlpZEr0V。当它们应该相等时的不同结果。

我想我有一个错误的 Arduino RC4 实现。我正在使用这个https://github.com/adamvr/arduino-base64

这是代码:

阿杜诺

#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);  
    }  
  ?>  
4

3 回答 3

1

我遇到了同样的问题,我可以确认您在 Arduino 中的 RC4 功能是错误的,您可以改用它:

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];
    }
于 2014-06-18T09:21:48.483 回答
0

这是我正在使用的当前实现

#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;
};
;
于 2014-06-18T16:03:34.963 回答
0

经过多次尝试但没有成功,我最终得到了以下三个代码:

  • Arduino代码实现RC4(改编自此C代码)并将加密结果编码为Base64
  • 解码base64和解密RC4的PHP代码
  • 用于测试 PHP 的 HTML(最终它将成为 ESP32 Webserver 的索引)。注意力!在 URL 中发送 Base64 可能很危险,因为这些字符'+' '/' '='可能会产生问题,因此请确保您阅读这篇文章Base64 in url并且可能有问题的字符替换为'.' '_' '-'

在撰写本文时,我正在为 ESP32 版本 2.0.0 使用 Arduino 内核,请考虑如果您不使用此版本的 Base64.h,可能存在不兼容问题(此处有更多详细信息

Arduino代码

#include <stdio.h>
#include <string.h>
#include "base64.h"

typedef unsigned long ULONG;

void rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) 
{
    int i =0, j = 0;
    char k[256] = {0};
    unsigned char tmp = 0;
    for (i=0;i<256;i++) {
        s[i] = i;
        k[i] = key[i%Len];
    }
    for (i=0; i<256; i++) {
        j=(j+s[i]+k[i])%256;
        tmp = s[i];
        s[i] = s[j]; 
        s[j] = tmp;
    }
 }

void rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) 
{
    int i = 0, j = 0, t = 0;
    unsigned long k = 0;
    unsigned char tmp;
    for(k=0;k<Len;k++) {
        i=(i+1)%256;
        j=(j+s[i])%256;
        tmp = s[i];
        s[i] = s[j]; 
        s[j] = tmp;
        t=(s[i]+s[j])%256;
        Data[k] ^= s[t];
     }
} 

int main()
{ 
    unsigned char s[256] = {0}; //S-box
    char key[256] = "Hello";
    char pData[512] = "secretMsg";
    ULONG len = strlen(pData);
    printf("key : %s\n", key);
    printf("raw : %s\n", pData);
    
    rc4_init(s,(unsigned char *)key,strlen(key)); 
    rc4_crypt(s,(unsigned char *)pData,len);
    printf("encrypt  : %s\n", pData);

    base64 b;
    
    String encoded = b.encode((unsigned char *)pData, strlen(pData));
        
    Serial.println(encoded);
 
    rc4_init(s,(unsigned char *)key, strlen(key)); 
    rc4_crypt(s,(unsigned char *)pData,len);
    printf("decrypt  : %s\n",pData);

    
    
    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_URL_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>
于 2021-09-30T10:07:11.660 回答