【发布时间】:2019-08-21 20:46:48
【问题描述】:
我正在尝试在 python 中记录音频原始数据,加密数据并将其发送到 .NET 服务器,在那里我解密接收到的数据并转换为字节数组。当我将接收到的数据转换为像 Encoding.ASCII.GetBytes(decryptedData) 这样的字节数组时,一切几乎都在工作。但最大字节值为63,发送数据最大字节值为255。发送和接收数据示例:
发送数据
3, 0, 3, 0, 3, 0, 4, 0, 4, 0, 2, 0, 252, 255, 1, 0, 255, 255, 1, 0, 0, 0...
收到的数据
3, 0, 3, 0, 3, 0, 4, 0, 4, 0, 2, 0, 63, 63, 1, 0, 63, 63, 1, 0, 0, 0...
当我将接收到的数据转换为像这样 Encoding.UTF8.GetBytes(DecryptData(aes, data)) 的字节数组时,一切几乎都在工作。但高价值就不一样了。发送和接收数据示例:
发送数据
6, 0, 8, 0, 250, 255, 255, 255, 3, 0, 6, 0, 2, 0, 4, 0, 3, 0, 6, 0, 3, 0...
收到的数据
6、0、8、0、239、191、189、239、191、189、239、191、189、239、191、189、3、0、6、0、2、0、4、0 , 3, 0, 6, 3, 0...
似乎转换会产生更多变量。我不知道。
这里是记录、加密和发送数据的python代码:
import pyaudio
import sys
import socket
import struct
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
key = b"bpjAqrgO2N8q7Rfj8IHzeRxmP1W4HwUTWCRi7DQgyDc="
iv = b"Ta6e1cZAWQMM0QI66JC74w=="
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
pya = pyaudio.PyAudio()
stream = pya.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, output=True, frames_per_buffer=chunk)
print ("recording")
for i in range(0, 44100 // chunk * RECORD_SECONDS):
data = stream.read(chunk)
print (struct.unpack('{}B'.format(len(data)), data))
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cipher_suite = AES.new(base64.urlsafe_b64decode(key), AES.MODE_CBC, base64.urlsafe_b64decode(iv))
cipher_text = cipher_suite.encrypt(pad(data, 16))
sock.sendto(cipher_text, (UDP_IP, UDP_PORT))
input ()
# check for silence here by comparing the level with 0 (or some threshold) for
# the contents of data.
# then write data or not to a file
print ("done")
stream.stop_stream()
stream.close()
pya.terminate()
这是接收、解密和转换数据的C#代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace DOTNETServer
{
class Program
{
private static string IP = "127.0.0.1";
private static int Port = 5005;
private static string Key = "bpjAqrgO2N8q7Rfj8IHzeRxmP1W4HwUTWCRi7DQgyDc=";
private static string IV = "Ta6e1cZAWQMM0QI66JC74w==";
static void Main(string[] args)
{
UDPServer(IPAddress.Parse(IP), Port);
Console.ReadKey();
}
private static void UDPServer(IPAddress IP, int Port)
{
byte[] data = new byte[32768];
IPEndPoint endPoint = new IPEndPoint(IP, Port);
UdpClient client = new UdpClient(endPoint);
SymmetricAlgorithm aes = new AesManaged();
aes.KeySize = 256;
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
while (true)
{
Console.WriteLine("Waiting for data.");
data = client.Receive(ref endPoint);
var convertedReceivedData = Encoding.ASCII.GetBytes(DecryptData(aes, data));
Console.Write("(");
foreach(var item in convertedReceivedData)
{
Console.Write(item + ", ");
}
Console.Write(")");
}
}
static byte[] EncryptText(SymmetricAlgorithm aesAlgorithm, string text)
{
ICryptoTransform encryptor = aesAlgorithm.CreateEncryptor(aesAlgorithm.Key, aesAlgorithm.IV);
byte[] data = new byte[32768];
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(cs))
{
writer.Write(text);
}
}
data = ms.ToArray();
}
return data;
}
static string DecryptData(SymmetricAlgorithm aes, byte[] data)
{
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] encryptedDataBuffer = data;
string plainText = "";
using (MemoryStream ms = new MemoryStream(encryptedDataBuffer))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader reader = new StreamReader(cs))
{
plainText = reader.ReadToEnd();
}
}
}
return plainText;
}
}
}
【问题讨论】:
-
服务器中的代码表明解密的数据由文本字符组成(否则为什么要在解密的数据流上使用 StreamReader,对吧?)。但是您的 Python 代码表明(据我所知)加密数据是音频样本的“原始二进制”字节。因此,除非我忽略了某些东西或我错了,否则您的服务器代码在概念层面上与您的客户端代码不匹配,因为服务器代码似乎期望与 Python 客户端提供的加密数据(文本)不同类型(非文本字节)。
-
请注意,文本字符不是字节的同义词,反之亦然。根据所使用的文本编码,并非所有可能的字节值都可以转换为一个字符(例如使用 ASCII),或者多个字节(多个字节)将仅转换为一个字符(例如使用 UTF-8)。如果您想将字节数据作为字节数据进行处理,为什么还要尝试将字节数据解释/处理为文本?
-
顺便说一下,关于为什么会出现值 63 的旁注:63 是字符
?的 ASCII 值,它显然被用作替代字符通过 Encoding.ASCII.GetBytes 对“plainText”字符串中不是有效 ASCII 字符的任何字符。 -
是的,我知道这一点,但如果我没记错的话,这并不重要。我虽然当我将字符串转换回字节数组时它是一样的......可能不是......对于像文本,字符串这样的普通消息,在客户端上转换为字节数组然后加密和发送然后接收和解密之后,消息很好。我虽然这只是关于字节数组转换。而且 CryptoStream 不支持 Write...我可能会尝试另一种解密方式...
-
从不,从不,从不将二进制数据编码。它会破坏数据。删除不可打印字符的 ASCII 编码,这将使得无法重新创建原始数据。您可以转换为 64 位流,它是可逆的,将 gt 原始数据。
标签: c# python .net encryption type-conversion