【问题标题】:Arduino AES128 encryption - C# decryption padding problemArduino AES128 加密 - C# 解密填充问题
【发布时间】:2020-04-07 03:56:16
【问题描述】:

我需要单向加密通信。 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#) 相同,还是其他地方的错误?

【问题讨论】:

    标签: visual-studio encryption arduino aes badpaddingexception


    【解决方案1】:

    这里有几个问题。

    • Arduino:你应该每次随机生成一个IV,并与消息一起发送。
    • Arduino:你在整数表达式上使用round,这只是浪费。删除round这个词不会改变任何答案(但它会删除浮点数学并可能避免打开芯片的浮点部分,从而节省电力)。
    • Arduino:您正在制作与输入大小相同的 base64 输出缓冲区 (encoded)。 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/W21RJABase64(AES-CBC-Encrypt(key: unhex("01020304050607080901020304050607"), iv: unhex("07060504030201090807060504030201"), message: ASCII("24051984"))的输出为pArfBo2HLU9+DXGhFPJDFg==

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

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

    【讨论】:

    • 你说得对,问题出在Arduino方面,现在已经用你提供的数据进行了测试。主要目标是将软件“锁定”到 arduino,因为该软件比 arduino 硬件昂贵得多,而且我会防止复印机制造与我相同的设备并使用我的软件。老实说,我不认为来自中国的中型复印机公司会花费大量超级计算机 CPU 时间来破解我的加密以接收 kay 并将其编程到他的 arduino 复制硬件中。
    猜你喜欢
    • 2011-03-12
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    相关资源
    最近更新 更多