1

我需要单向加密通信。arduino 加密消息并通过串行将其发送到 C# 程序进行解密。

用于加密的 arduino 代码如下所示:

#include <Crypto.h>
#include <base64.hpp>
#define BLOCK_SIZE 16
uint8_t key[BLOCK_SIZE] = { 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7 };
uint8_t iv[BLOCK_SIZE] = { 7,6,5,4,3,2,1,9,8,7,6,5,4,3,2,1 };

void bufferSize(char* text, int &length)
{
  int i = strlen(text);
  int buf = round(i / BLOCK_SIZE) * BLOCK_SIZE;
  length = (buf <= i) ? buf + BLOCK_SIZE : length = buf;
}
void encrypt(char* plain_text, char* output, int length)
{
  byte enciphered[length];
  AES aesEncryptor(key, iv, AES::AES_MODE_128, AES::CIPHER_ENCRYPT);
  aesEncryptor.process((uint8_t*)plain_text, enciphered, length);
  int encrypted_size = sizeof(enciphered);
  char encoded[encrypted_size];
  encode_base64(enciphered, encrypted_size, (unsigned char*)encoded);
  strcpy(output, encoded);
}

加密的消息是:

jEYGnz3TYm+aWveh8wNATw==

明文消息是:

24051984

在 PC 端,我在 Visual Studio 中有下一个代码:

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;
using System.Security.Cryptography;


namespace BaseReadSerial
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = SerialPort.GetPortNames();
            cBoxComPort.Items.AddRange(ports);
        }

        private void groupBox1_Enter(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            try 
            {
                serialPort1.PortName = cBoxComPort.Text;
                serialPort1.DtrEnable = true;
                serialPort1.ReadTimeout = 5000;
                serialPort1.WriteTimeout = 500;
                serialPort1.Open();
                lblStatusCom.Text = "On";
                lblMessage.Text = "I am on!";
            }
            catch(Exception err)
            {
                MessageBox.Show(err.Message,"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                lblStatusCom.Text = "Off";
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if(serialPort1.IsOpen)
            {
                //string mgs1 = serialPort1.ReadLine();
                string mgs1 = "jEYGnz3TYm+aWveh8wNATw==";
                serialPort1.Close();
                lblStatusCom.Text = "Off";
                string base64Decoded;
                byte[] data = System.Convert.FromBase64String(mgs1);
                base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data);
                //Start
                var str = base64Decoded;
                var aes = new SimpleAES();
                var encryptStr = aes.Encrypt(str);
                var decryptStr = aes.Decrypt(mgs1);
                //End
                lblMessage.Text = decryptStr;

            }
        }

        private void label1_Click(object sender, EventArgs e)
        {
            Text = "Off";
        }

        private void lblStatusCom_Click(object sender, EventArgs e)
        {

        }

        private void cBoxComPort_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

        }

        private void lblMessage_Click(object sender, EventArgs e)
        {

        }
    }
    public class SimpleAES
    {
        private byte[] key = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 };
        private byte[] vector = { 7, 6, 5, 4, 3, 2, 1, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
        private readonly ICryptoTransform encryptor;
        private readonly ICryptoTransform decryptor;
        private readonly UTF8Encoding encoder;

        public SimpleAES()
        {
            var rm = new RijndaelManaged();
            encryptor = rm.CreateEncryptor(key, vector);
            decryptor = rm.CreateDecryptor(key, vector);
            encoder = new UTF8Encoding();
        }

        public string Encrypt(string unencrypted)
        {
            return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted)));
        }

        public string Decrypt(string encrypted)
        {
            return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
        }

        public byte[] Encrypt(byte[] buffer)
        {
            return Transform(buffer, encryptor);
        }

        public byte[] Decrypt(byte[] buffer)
        {
            return Transform(buffer, decryptor);
        }

        protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
        {

            using (var stream = new MemoryStream())
            {
                using (var cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
                {
                    cs.Write(buffer, 0, buffer.Length);
                }
                return stream.ToArray();
            }
        }

    }
}

触发条件发生后,我收到一条错误消息:

System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'

如果我认为正确,uint8_t (Arduino) 与byte[] (Visual Studio C#) 相同,还是其他地方的错误?

4

1 回答 1

1

这里有几件事是错误的。

  • Arduino:您应该每次都随机生成一个 IV,并与消息一起发送。
  • Arduino:您使用round的是整数表达式,这很浪费。删除这个词round不会改变任何答案(但它会删除浮点数学并可能避免打开芯片的浮点部分,从而节省电力)。
  • Arduino:您正在制作encoded与输入大小相同的 base64 输出缓冲区 ( )。Base64 增长了 4/3 ( (size + 2) / 3 * 4),所以你正在做一个缓冲区溢出。要么使缓冲区更大,要么直接将事物和 base64 编码为output.
    • 旁白:您不接受output. 希望够大。
  • C#:(一旦你让Arduino发送它,你需要阅读每条消息的IV)
  • C#:您将每个加密器和解密器保存一次。每次手术后都需要重建它们(将 IV 放回原处)。
  • 两者:硬编码的密钥几乎没有安全性。您将希望获得随机会话密钥。(ECDH 密钥协议/PC 发送 RSA 公钥,Arduino 生成随机 AES 密钥,用 RSA / 等加密发送回)。

假设你的输入/键/IV/输出在你运行时,你在 Arduino 代码的某个地方有一个错误。根据https://cryptii.com/pipes/W21RJA的输出Base64(AES-CBC-Encrypt(key: unhex("01020304050607080901020304050607"), iv: unhex("07060504030201090807060504030201"), message: ASCII("24051984"))pArfBo2HLU9+DXGhFPJDFg==

当您可以从 cryptii.com 之类的网站和 Arduino 上的加密代码获得相同的答案时,您可以继续进行解密逻辑(然后是随机 IV)。

FWIW,加密串行对我来说没有多大意义。没有不受信任的腿,您可以在 6 英尺长的电缆上轻松监控 MITM...

于 2019-12-13T18:31:27.187 回答