我需要在Flutter移动应用程序中解密AES(PKCS#7)编码的字符串。
该字符串是从QR代码获取的,该QR代码是从Java应用程序生成的,并且包含AES编码的字符串。
Java编码:
import java.security.Security;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class MyClass {
public static void main(String[] args) throws Exception {
String toEncode = "firstname.lastname@mycompany.com;12";
String encoded = pleaseEncodeMe(toEncode);
System.out.println(encoded);
}
private static String pleaseEncodeMe(String plainText) throws Exception {
Security.addProvider(new BouncyCastleProvider());
final String encryptionAlgorithm = "AES/CBC/PKCS7PADDING";
final String encryptionKey = "WHatAnAWEsoMeKey";
final SecretKeySpec keySpecification = new SecretKeySpec(encryptionKey.getBytes(StandardCharsets.UTF_8), encryptionAlgorithm);
final Cipher cipher = Cipher.getInstance(encryptionAlgorithm, "BC");
cipher.init(Cipher.ENCRYPT_MODE, keySpecification);
final byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
return Base64.encodeBase64URLSafeString(encryptedBytes);
}
}
输出:AIRTEuNmSuQtYuysv93w3w83kJJ6sg7kaU7XzA8xrAjOp-lKYPp1brtDAPbhSJmT
Dart解码:
void main() {
print(decodeMeOrDie("AIRTEuNmSuQtYuysv93w3w83kJJ6sg7kaU7XzA8xrAjOp-lKYPp1brtDAPbhSJmT"));
}
String decodeMeOrDie(String encryptedString) {
final key = Key.fromUtf8("WHatAnAWEsoMeKey");
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key, mode: AESMode.cbc, padding: "PKCS7"));
return encrypter.decrypt64(encryptedString, iv: iv);
}
输出:Y��=X�Rȑ�"Qme@mycompany.com;12
您会看到只有一部分字符串被解码。
答案 0 :(得分:2)
必须考虑两点:
1)对于解密,需要用于加密的IV。
2)出于安全原因,必须为每种加密随机生成一个新的IV,以便同一密钥here不能多次使用IV。
因此,IV必须从加密侧传递到解密侧。这不是自动发生的,而是必须实现。
一种可能性是连接IV和密文的字节数组。通常,IV放在密文之前,并且结果是Base64编码的(如果需要),例如在Java中:
// Concatenate IV and ciphertext
byte[] iv = ...
byte[] ciphertext = ...
byte[] ivAndCiphertext = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, ivAndCiphertext, 0, iv.length);
System.arraycopy(ciphertext, 0, ivAndCiphertext, iv.length, ciphertext.length);
// If required: Base64-encoding
此数据传输到解密端,后者在Base64解码后将两个部分分开。对于AES-CBC,IV为16个字节长,因此前16个字节代表IV,其余为密文。 IV不需要加密,因为它不是秘密的。
具体针对您的情况,这意味着您必须在Java端将IV和密文连接起来,并对结果进行Base64编码。在Dart端,您必须先进行Base64解码,然后才能将IV和密文这两个部分分开并用于随后的解密。
有两种在加密之前生成IV的方法:如您的示例所示,由Cipher
实例进行隐式生成,或者例如通过显式生成。通过SecureRandom。 here讨论了这两种选择。如果IV是通过Cipher
实例隐式生成的,则此IV必须通过Cipher
实例确定,因为以后需要解密:
// Determine IV from cipher for later decryption
byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
如果明确确定了IV(例如,使用SecureRandom
),则必须将其传递到Cipher
实例,以便将其用于正在运行的加密中。这是通过IvParameterSpec
完成的。
// Assign IV to cipher so that it is used for current encryption
byte[] iv = ...
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretkeySpec, ivParameterSpec);
硬编码密钥通常不是一个好习惯(也许出于测试目的)。但是,密钥生成/管理的主题不在此答案的范围内。关于这个主题已经有很多疑问和答案。如果这些答案未涵盖您的问题,请发布新问题。硬编码的IV不会在上述架构内出现,而应仅用于测试目的。
答案 1 :(得分:0)
如果可以帮助某人,这是我最后用dart编写的代码(它使用#include <stdio.h>
__global__ void fetch(cudaTextureObject_t tex, std::size_t width, std::size_t height)
{
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
float u = (i + 0.5f) / width;
float v = (j + 0.5f) / height;
auto p = tex2D<uchar4>(tex, u, v);
printf("i=%d, j=%d -> u=%3.2f, v=%3.2f, r=%d, g=%d, b=%d, a=%d\n", i, j, u, v, p.x, p.y, p.z, p.w);
// -> always returns p = {0, 0, 0, 0}
}
}
}
int main() {
constexpr std::size_t width = 2;
constexpr std::size_t height = 2;
// creating a dummy texture
uchar4 image[width*height];
for(std::size_t j = 0; j < height; ++j) {
for(std::size_t i = 0; i < width; ++i)
image[j*width+i] = make_uchar4(255*j/height, 255*i/width, 55, 255);
}
cudaArray_t cuArray;
auto channelDesc = cudaCreateChannelDesc<uchar4>();
cudaMallocArray(&cuArray, &channelDesc, width, height);
cudaMemcpy2DToArray(cuArray, 0, 0, image, width*sizeof(uchar4), width*sizeof(uchar4), height, cudaMemcpyHostToDevice);
struct cudaResourceDesc resDesc;
memset(&resDesc, 0, sizeof(resDesc));
resDesc.resType = cudaResourceTypeArray;
resDesc.res.array.array = cuArray;
struct cudaTextureDesc texDesc;
memset(&texDesc, 0, sizeof(texDesc));
texDesc.addressMode[0] = cudaAddressModeBorder;
texDesc.addressMode[1] = cudaAddressModeBorder;
texDesc.filterMode = cudaFilterModeLinear;
texDesc.readMode = cudaReadModeElementType;
texDesc.normalizedCoords = 1;
cudaTextureObject_t texObj = 0;
cudaCreateTextureObject(&texObj, &resDesc, &texDesc, NULL);
fetch<<<1, 1>>>(texObj, width, height);
cudaDeviceSynchronize();
cudaDestroyTextureObject(texObj);
cudaFreeArray(cuArray);
return 0;
}
包):
encrypt