我已经读过,如果你想使用一种编程语言加密字符串并使用另一种编程语言解密该字符串,那么为了确保兼容性,最好在进行加密之前进行一些转换。我已经读过,加密字符串的字节数组而不是字符串本身是最佳做法。此外,我已经读过某些加密算法希望每个加密数据包的大小固定。如果要加密的最后一个数据包不是所需的大小,则加密将失败。因此,加密首先转换为固定长度的数据(如十六进制)似乎是个好主意。
我试图找出通常有用的最佳实践,无论使用何种加密算法。为了在跨不同语言和平台加密和解密数据时最大限度地提高兼容性,我想对以下步骤进行批评:
加密:
解密:
你的前提是正确的,但在某些方面它比这更容易。现代加密算法意味着语言不可知,如果你有相同的输入和相同的键,你应该得到相同的结果。
确实,对于大多数密码和some modes,数据需要是固定长度的。转换为十六进制不会这样做,因为数据需要以固定边界结束。例如,对于AES,如果要加密4个字节,则需要将其填充为16个字节,这是十六进制表示不能执行的。幸运的是,最有可能发生在你最终使用的加密API中,使用标准的padding schemes之一。由于您没有标记语言,因此.NET支持的AesManaged类的填充模式的here's a list。
另一方面,正确加密数据需要的不仅仅是字节编码。您需要选择正确的操作模式(首选CBC或CTR),然后提供某种类型的message integrity。仅加密并不能防止篡改数据。如果你想简化一些事情,那么看看像GCM这样的模式,它可以处理机密性和完整性。
你的方案应该是这样的:
用于解密:
我已经读过,加密字符串的字节数组而不是字符串本身是最佳做法。
加密算法通常用于字节数组或字节流,所以是的。您不直接加密对象(字符串),加密其数据表示。
此外,我已经读过某些加密算法希望每个加密数据包的大小固定。如果要加密的最后一个数据包不是所需的大小,则加密将失败。
这是您选择的特定加密算法的实现细节。这实际上取决于API接口对算法的影响。
一般来说,是的,隐藏算法会将输入分解为固定大小的块。如果最后一个块未满,那么它们可以用任意字节填充结尾以获得完整的块。为了区分填充数据和恰好在末尾具有看起来像填充字节的数据,它们将前缀或附加明文的长度添加到字节流中。
这是一种不应该留给用户的细节,一个好的加密库将为您处理这些细节。理想情况下,您只想输入纯文本字节并在另一端获取加密字节。
因此,加密首先转换为固定长度的数据(如十六进制)似乎是个好主意。
将字节转换为十六进制不会使其固定长度。它的大小增加了一倍,但这并不固定。它使ASCII安全,因此可以轻松地嵌入到文本文件和电子邮件中,但这与此无关。 (而且Base64是一个比十六进制更好的二进制→ASCII编码。)
为了确定确保与跨不同语言和平台的数据加密和解密兼容的最佳实践,我想对以下步骤进行批评:
加密:
- 纯文本字符串
- 将纯文本字符串转换为字节数组
- 将字节数组转换为十六进制
- 将十六进制加密为加密字符串
- 加密字串
- 纯文本字节数组到加密字节数组
解密:
- 加密字串
- 将加密字符串解密为十六进制
- 将十六进制转换为字节数组
- 加密字节数组
- 将加密的字节数组解密为纯文本字节数组
- 将字节数组转换为纯文本字符串
- 纯文本字符串
要加密,将纯文本字符串转换为其字节表示,然后加密这些字节。结果将是一个加密的字节数组。
以您选择的方式将字节数组传输到另一个程序。
要解密,请将加密的字节数组解密为纯文本字节数组。从这个字节数组构造你的字符串。完成。
实际上,加密的最佳实践是使用高级加密框架,使用基元可以做很多错误。如果您不使用高级加密框架,mfanto可以很好地提及您需要知道的重要事项。我猜测,如果你试图最大限度地提高编程语言的兼容性,那是因为你需要其他开发人员与加密互操作,然后他们需要学习使用加密的低级细节。
因此,我对高级框架的建议是使用Google Keyczar框架,因为它可以为您处理细节,算法,密钥管理,填充,iv,身份验证标记,有线格式。它存在许多不同的编程Java, Python, C++,C#和Go。看看这个。
我编写了C#版本,所以我可以告诉你它在幕后使用的原语在大多数其他编程语言中也可以广泛使用,并且它使用像json这样的标准来进行密钥管理和存储。
我为此目的使用HashIds。它很简单,支持多种编程语言。每当我们需要解密目标中的数据时,我们使用它在我们的PHP,Node.js和Golang微服务之间传递加密数据。