All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.siisise.security.block.AESLong Maven / Gradle / Ivy
/*
* Copyright 2023 Siisise Net.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.siisise.security.block;
import net.siisise.lang.Bin;
/**
* Adbanced Encryption Standard.
* FIPS 197
* Rijndael という名称.
*
* ソフト実装で他より速いはず。
* 安全(テーブル使用なので計算差なし)。
*
* https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf
* RoundKey参考
* https://qiita.com/tobira-code/items/152befa86bd515f67241
* MixColumns
* https://tex2e.github.io/blog/crypto/aes-mix-columns
*/
public class AESLong extends OneBlock {
/**
* Rijndael 128~256ビット 32ビット単位
* AESLong 128bit固定
*/
private final int blockLength = 128;
private static final int[] Rcon = new int[11];
private static final int[] sbox = new int[256];
private static final int[] MIX0 = new int[256];
private static final int[] MIX1 = new int[256];
private static final int[] MIX2 = new int[256];
private static final int[] MIX3 = new int[256];
private static final int[] ibox = new int[256];
private static final int[] IMIX0 = new int[256];
private static final int[] IMIX1 = new int[256];
private static final int[] IMIX2 = new int[256];
private static final int[] IMIX3 = new int[256];
/**
* ラウンド鍵
*/
private int[] w;
static {
// 2・n
final int[] GF = new int[256];
final int[] logGF = new int[256];
final int[] expGF = new int[256];
// テーブルにしてしまうといろいろ省略できる 使い捨てだが関数でもいい
for (int i = 1; i < 256; i++) {
// 1と1bに分けずにシフト演算でまとめる
GF[i] = (i << 1) ^ ((i >> 7) * 0x11b);
} // m(x) = x^8 + x^4 * x^3 + x + 1 のビット 100011011 = 0x11b
// sboxつくる
// https://tociyuki.hatenablog.jp/entry/20160427/1461721356
// を元に高速化したもの
int n = 1;
for (int e = 0; e < 255; e++) {
logGF[n] = e;
expGF[e] = n;
n ^= GF[n]; // 3・n
}
logGF[0] = 0;
expGF[255] = expGF[0];
for (int i = 0; i < 256; i++) {
// r ガロア体の逆数変換 1回しか使わないので使い捨て
int r = (i == 0) ? 0 : expGF[255 - logGF[i]]; // むつかしいところ
int s = r ^ (r << 1) ^ (r << 2) ^ (r << 3) ^ (r << 4);
s = 0x63 ^ (s ^ (s >> 8)) & 0xff; // 手抜きローテート
sbox[i] = s;
/*
// 個別で逆も計算できるが省略
r = (i << 1) ^ (i << 3) ^ (i << 6) ^ 0x5;
r = (r ^ ( r >> 8)) & 0xff;
ibox[i] = (r == 0) ? 0 : expGF[255 - logGF[r]];
/*/
ibox[s] = i;
//*/
int gf = GF[s]; // 前段階のsboxを含める
// 1,2,3しかないのに個別に mulとかしてはいけない
// XOR で演算できるので 3は1と2を合成するだけ
// sbox込み あとで XOR できるところまで計算
MIX0[i] = s * 0x00010101 ^ gf * 0x01000001;
MIX1[i] = s * 0x01000101 ^ gf * 0x01010000;
MIX2[i] = s * 0x01010001 ^ gf * 0x00010100;
MIX3[i] = s * 0x01010100 ^ gf * 0x00000101;
// 同じ原理で個別の計算を省略する
gf = GF[i];
int gf4 = GF[gf];
int gf7 = gf4 ^ gf ^ i;
int gf9x = (GF[gf4] ^ i) * 0x01010101;
// iboxなし
IMIX0[i] = gf9x ^ (gf7 << 24) ^ gf ^ (gf4 << 8);
IMIX1[i] = gf9x ^ (gf7 << 16) ^ (gf << 24) ^ gf4 ;
IMIX2[i] = gf9x ^ (gf7 << 8) ^ (gf << 16) ^ (gf4 << 24);
IMIX3[i] = gf9x ^ gf7 ^ (gf << 8) ^ (gf4 << 16);
}
n = 1;
for (int i = 1; i < 11; i++) { // 使う範囲で生成
Rcon[i] = n << 24;
n = GF[n];
}
}
@Override
public int getBlockLength() {
return blockLength;
}
/**
* subWord(rotate(t))
* @param t
* @return
*/
private static int rotsubWord(int t) {
return sbox[t >> 16 & 0xff] << 24
| sbox[t >> 8 & 0xff] << 16
| sbox[t & 0xff] << 8
| sbox[t >>> 24 ];
}
/**
*
* @param word
* @return
*/
private static int subWord(int word) {
return sbox[word >>> 24 ] << 24
| sbox[word >> 16 & 0xff] << 16
| sbox[word >> 8 & 0xff] << 8
| sbox[word & 0xff];
}
private static final int Nb = 4;
private int Nr4;
/**
* 鍵.
* AESは128bit長.
*
* @param key 128,192,256bit (16,24,32byte)のいずれか
*/
public void init(byte[] key) {
if (key.length != 16 && key.length != 24 && key.length != 32) {
throw new SecurityException("key length");
}
int Nk = key.length / 4; // ぐらい
int Nr = Nk + 6;
Nr4 = Nr * 4;
// ラウンドキーの初期化 ワード列版 128*11?
w = new int[Nb * (Nr + 1)];
Bin.btoi(key, 0, w, Nk);
int temp;
for (int i = Nk; i < Nb * (Nr + 1); i++) {
temp = w[i - 1];
if (i % Nk == 0) {
temp = rotsubWord(temp) ^ Rcon[i / Nk];
} else if (Nk > 6 && i % Nk == 4) {
temp = subWord(temp);
}
w[i] = w[i - Nk] ^ temp;
}
}
/*
private static void btoi(final byte[] src, int offset, int[] dst, int length) {
for (int i = 0; i < length * 4; i += 4) {
int t = offset + i;
dst[i / 4]
= ( src[t ] << 24)
| ((src[t + 1] & 0xff) << 16)
| ((src[t + 2] & 0xff) << 8)
| (src[t + 3] & 0xff);
}
}
private static byte[] itob(final int[] src) {
byte[] ss = new byte[16];
for (int i = 0; i < 4; i++) {
int l = i*4;
ss[l ] = (byte) (src[i] >> 24);
ss[l + 1] = (byte) (src[i] >> 16);
ss[l + 2] = (byte) (src[i] >> 8);
ss[l + 3] = (byte) src[i] ;
}
return ss;
}
*/
/**
* 複数パラメータは持たない
*
* @param key
*/
@Override
public void init(byte[]... key) {
throw new SecurityException();
}
/**
* Sec. 5.2.
*
* @param s
* @param round
*/
private void addRoundKey(int[] s, int round) {
for (int c = 0; c < 4; c++) {
s[c] ^= w[round + c];
}
}
private void addRoundKey(byte[] src, int offset, int[] s, int round) {
// round *= 4;
System.arraycopy(w, round, s, 0, 4);
for ( int i = 0; i < 4; i++ ) {
int t = offset + i*4;
s[i] ^= ( ((src[t ] & 0xff) << 24)
| ((src[t+1] & 0xff) << 16)
| ((src[t+2] & 0xff) << 8)
| (src[t+3] & 0xff));
}
}
/**
* ShiftRows() の逆 + SubBytes() の逆.
*/
private static void invShiftSub(int[] s) {
int a = s[0], b = s[1], c = s[2], d = s[3];
int e, f, g, h;
e = ibox[a >>> 24 ] << 24
^ ibox[d >> 16 & 0xff] << 16;
e ^= ibox[c >> 8 & 0xff] << 8;
e |= ibox[b & 0xff];
f = ibox[b >>> 24 ] << 24
^ ibox[a >> 16 & 0xff] << 16;
f ^= ibox[d >> 8 & 0xff] << 8
^ ibox[c & 0xff];
g = ibox[c >>> 24 ] << 24
^ ibox[b >> 16 & 0xff] << 16;
g ^= ibox[a >> 8 & 0xff] << 8;
g ^= ibox[d & 0xff];
h = ibox[d >>> 24 ] << 24
^ ibox[c >> 16 & 0xff] << 16;
h ^= ibox[b >> 8 & 0xff] << 8;
h ^= ibox[a & 0xff];
s[0] = e;
s[1] = f;
s[2] = g;
s[3] = h;
}
/**
* MixColumns() の逆.
*/
private static void invMixColumns(int[] s) {
for (int c = 0; c < 4; c++) {
int d = s[c];
s[c] = IMIX0[d >>> 24 ]
^ IMIX1[d >> 16 & 0xff]
^ IMIX2[d >> 8 & 0xff]
^ IMIX3[d & 0xff];
}
}
/**
* AESLong エンコード
AMD Ryzen 5 2600X で AESLong/CBCで 950Mbpsを超える
*
* @param src source 16byte
* @param offset 先頭位置
*/
@Override
public byte[] encrypt(final byte[] src, final int offset) {
int t = offset;
// AddRoundKey
int a = w[0], b = w[1], c = w[2], d = w[3];
for (int i = 0; i < 4; i++) {
int n = 24 - 8 * i;
a ^= ((src[t ] & 0xff) << n);
b ^= ((src[t + 4] & 0xff) << n);
c ^= ((src[t + 8] & 0xff) << n);
d ^= ((src[t + 12] & 0xff) << n);
t++;
}
// SubBytes + ShiftRow + MixColumns
for (int r4 = 4; r4 < Nr4; r4 += 4) {
int e, f, g;
e = MIX0[ a >>> 24 ]
^ MIX1[(b >> 16) & 0xff];
f = MIX0[ b >>> 24 ]
^ MIX1[(c >> 16) & 0xff];
g = MIX0[ c >>> 24 ]
^ MIX1[(d >> 16) & 0xff];
e ^= MIX2[(c >> 8) & 0xff]
^ MIX3[ d & 0xff];
f ^= MIX2[(d >> 8) & 0xff]
^ MIX3[ a & 0xff];
d = MIX0[ d >>> 24 ];
g ^= MIX2[(a >> 8) & 0xff]
^ MIX3[ b & 0xff];
d ^= MIX1[(a >> 16) & 0xff];
d ^= MIX2[(b >> 8) & 0xff];
d ^= MIX3[ c & 0xff];
// AddRoundKey
a = e ^ w[r4 ];
b = f ^ w[r4 + 1];
c = g ^ w[r4 + 2];
d ^= w[r4 + 3];
}
int e, f, g;
e = (sbox[ a >>> 24 ] << 24)
| (sbox[(b >> 16) & 0xff] << 16);
e |= (sbox[(c >> 8) & 0xff] << 8)
| sbox[ d & 0xff];
f = (sbox[ b >>> 24 ] << 24)
| (sbox[(c >> 16) & 0xff] << 16);
f |= (sbox[(d >> 8) & 0xff] << 8)
| sbox[ a & 0xff];
g = (sbox[ c >>> 24 ] << 24)
| (sbox[(d >> 16) & 0xff] << 16);
g |= (sbox[(a >> 8) & 0xff] << 8)
| sbox[ b & 0xff];
d = (sbox[ d >>> 24 ] << 24)
| (sbox[(a >> 16) & 0xff] << 16)
| (sbox[(b >> 8) & 0xff] << 8)
| sbox[ c & 0xff];
// AddRoundKey
return Bin.itob( new int[] {
e ^ w[Nr4] ,
f ^ w[Nr4 + 1],
g ^ w[Nr4 + 2],
d ^ w[Nr4 + 3]
} );
}
@Override
public byte[] decrypt(final byte[] src, final int offset) {
int[] s = new int[4];
addRoundKey(src, offset, s, Nr4);
invShiftSub(s);
for (int r4 = Nr4 - 4; r4 >= 4; r4-=4) {
addRoundKey(s, r4);
invMixColumns(s);
invShiftSub(s);
}
addRoundKey(s, 0);
return Bin.itob(s);
}
}