我正在尝试用Java实现AES(仅限学术用途)。
我采用默认实现来将我的结果与原始结果进行比较。
private byte[] crypt(int mode, byte[] key, byte[] initializationVector, byte[] data)
{
try
{
SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initializationVector);
cipher.init(mode, secretKeySpec, ivParameterSpec);
return cipher.doFinal(data);
}
catch(BadPaddingException | InvalidKeyException | IllegalBlockSizeException | InvalidAlgorithmParameterException e)
{
throw new RuntimeException(e);
}
}
其中int模式为Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE。 注意,key,iv和data都是byte [](而不是char [])。
现在,当我尝试执行我的实现时,我遇到了Sboxes的问题。 我从维基百科中获取数组
https://en.wikipedia.org/wiki/Rijndael_S-box
例如,有unsigned char(例如C ++而不是Java)。
问题是:Java中的字节是否已签名(-128到127),因此当我想稍后将其用作数组索引时,其中一半是负数,导致问题的原因。
如果我将此sbox转换为byte [],那么我对数组的索引有疑问。 如果我决定在char []上做所有事情,那么我会将内存使用量加倍,而且我很难将我的结果与库存实现(使用byte [])进行比较。
我确信,实现股票加密的人比我聪明,所以我假设byte []是正确答案,但在这种情况下如何处理负数组索引?
当我需要非负表示时,我看到的唯一的是“偷偷摸摸”在byte和char之间进行转换,方法如下:
public class Sbox
{
// it's array from wiki, 256 elements
private final char substitute[] =
{
0x63, 0x7C, ... 0xBB, 0x16
};
public byte substitute(byte index)
{
return convert(substitute[convert(index)]);
}
private char convert(byte b)
{
return (char) (b < 0 ? b + 256 : b);
}
private byte convert(char c)
{
return (byte) (c < 256 ? c : 256 - c);
}
}
当需要索引和返回时 - 这不是最有效的想法,看起来像我的bug。
如何做得更好? 应该是byte []还是char []作为默认结构? (用于密钥/ iv /数据) 顺便说一句,只是为了确定,cipher.doFinal(数据); (在库存实施中)是进行全加密,而不仅仅是最终(非标准)轮次? 股票实施是否使用AES-NI?
如果重要:我在美国境外,我已经解锁了无限制的加密版本。