フグはAESよりもはるかに速いという理論を知っています。ただし、Java 8プラットフォームと弾力のある城のライブラリ)で、1 MB、5 MB、10 MBなどのファイルのaesとフグを含むいくつかのアルゴリズムをベンチマークしました。すべてのテストシナリオで、aesはフグよりも高速です。
どこで間違えたのかな?
ここにコードがあります:
private static final int WARMUP_COUNT = 5;
private static final int FILE_LENGTH = 1024*512;
private static final int ITERATOR_COUNT = 1000;
private static final double BOLME = 1_000_000.0 * (ITERATOR_COUNT-WARMUP_COUNT);
static final private byte[] ivBytes = new byte[] { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
private static final IvParameterSpec ivSpec16bytes = new IvParameterSpec(ivBytes);
private static final IvParameterSpec ivSpec8bytes = new IvParameterSpec(Arrays.copyOfRange(ivBytes,0,8));
static String[] algosWithMode = {"AES/CBC/PKCS7Padding","Blowfish/CBC/PKCS7Padding","CAST5/CBC/PKCS7Padding","DES/CBC/PKCS7Padding","DESede/CBC/PKCS7Padding", "IDEA/CBC/PKCS7Padding","ARC4", };
static String[] algos = { "AES","Blowfish","CAST5","DES", "DESede","IDEA","ARC4" };
static int[] keylenngth = {128,128,128,56, 168,128,128 };
@SuppressWarnings("unused")
public static void main(String[] args) throws Exception {
if(ITERATOR_COUNT <= WARMUP_COUNT )
throw new Exception("iterator count must be greater than warm up count iterator: "+ITERATOR_COUNT
+" warmup count :" + WARMUP_COUNT);
Security.addProvider(new BouncyCastleProvider());
Key key = null;
byte[] plainText=null;
byte[] cipherText=null;
byte[] decryptedText=null;
long startTime;
DecimalFormat df = new DecimalFormat("0.000");
for (int k = 0; k < 7; k++) {
long timeDec = 0,timeEnc = 0,timekey = 0;
long maxtimeDec = 0,maxtimeEnc = 0,maxtimekey = 0;
long mintimeDec = Long.MAX_VALUE,mintimeEnc = Long.MAX_VALUE,mintimekey = Long.MAX_VALUE;
long topDec = 0,topEnc = 0,topkey = 0;
for (int i = 0; i < ITERATOR_COUNT; i++) {
SecureRandom random= new SecureRandom();
plainText = random.generateSeed(FILE_LENGTH);
startTime=System.nanoTime();
KeyGenerator keyGen = KeyGenerator.getInstance(algos[k]);
keyGen.init(keylenngth[k],random);
key=keyGen.generateKey();
timekey=System.nanoTime()-startTime;
Cipher cipher=null;
if(k == 0){
cipher = Cipher.getInstance(algosWithMode[k]);
cipher.init(Cipher.ENCRYPT_MODE, key,ivSpec16bytes);
}else if(k == 6){
cipher = Cipher.getInstance(algosWithMode[k]);
cipher.init(Cipher.ENCRYPT_MODE, key);
}else{
cipher = Cipher.getInstance(algosWithMode[k]);
cipher.init(Cipher.ENCRYPT_MODE, key,ivSpec8bytes);
}
startTime=System.nanoTime();
cipherText = cipher.doFinal(plainText);
timeEnc=System.nanoTime()-startTime;
if(k == 0){
cipher = Cipher.getInstance(algosWithMode[k]);
cipher.init(Cipher.DECRYPT_MODE, key,ivSpec16bytes);
}else if(k== 6){
cipher = Cipher.getInstance(algosWithMode[k]);
cipher.init(Cipher.DECRYPT_MODE, key);
}else {
cipher = Cipher.getInstance(algosWithMode[k]);
cipher.init(Cipher.DECRYPT_MODE, key,ivSpec8bytes);
}
startTime=System.nanoTime();
cipher.doFinal(cipherText);
timeDec=System.nanoTime()-startTime;
if (i >= WARMUP_COUNT) {
if (maxtimeEnc < timeEnc)
maxtimeEnc = timeEnc;
if (maxtimeDec < timeDec)
maxtimeDec = timeDec;
if (maxtimekey < timekey)
maxtimekey = timekey;
if (mintimeEnc > timeEnc)
mintimeEnc = timeEnc;
if (mintimeDec > timeDec)
mintimeDec = timeDec;
if (mintimekey > timekey)
mintimekey = timekey;
topEnc += timeEnc;
topDec += timeDec;
topkey += timekey;
}
}
double avgEnc=topEnc/BOLME;
double avgDec=topDec/BOLME;
double avgKey=topkey/BOLME;
System.out.println("********************************************************"+algos[k]+"*****************************************************************");
System.out.println("Avg Enc :"+df.format(avgEnc)+" - "+" Avg Dec :"+df.format(avgDec)+"-"+" Avg Key :"+ df.format(avgKey));
System.out.println("Max Enc :"+df.format(maxtimeEnc/1_000_000.0)+" - "+" Max Dec :"+df.format(maxtimeDec/1_000_000.0)+"-"+" Max Key :"+ df.format(maxtimekey/1_000_000.0));
System.out.println("Min Enc :"+df.format(mintimeEnc/1_000_000.0)+" - "+" Min Dec :"+df.format(mintimeDec/1_000_000.0)+"-"+" Min Key :"+ df.format(mintimekey/1_000_000.0));
System.out.println();
//System.out.println();
}
}
理論的には、BlowfishはAESよりも高速であると想定されていますが、はるかに高速ではありません。詳細については この質問 を参照してください。
次にoptimizationがあります。与えられたアルゴリズムについて、その「最高速度」を最適なコードで達成されるパフォーマンスであると定義することができます。しかし、実際の実装は完全に最適化されることは決してなく、それらが最適化にどれほど(または遠く)近いかは、それらに費やされた努力に依存します。 AESは大きく、頻繁に使用されます。そのため、AES実装を作成する人々は、最新のものを含め、ほとんどのアーキテクチャで高速になるようにコードを調整するよう注意しています。一方、Blowfishは、十分な理由で使用ベースが減少しています(64ビットのブロックがあり、ギガバイトのデータが特定のキーで暗号化されている場合、セキュリティを確保するのに十分な大きさではありません)。したがって、特定の暗号ライブラリでは、AES実装はBlowfish実装よりも最適化および保守されている可能性が高いと想定できます。
その他のポイント:
Blowfishの暗号化は高速ですが、key schedule(大量のデータを処理する準備が整った内部テーブルにキーを変換する)は、Blowfishでは非常に低速です。コードでは、暗号化の速度を「全体として」測定しようとしているように見えます。未加工の暗号化速度を測定する場合は、まず1メガバイトを暗号化する必要があります(キースケジュールが発生し、すべてのキャッシュにデータが入力されていることを確認するため)。次に、暗号化の速度を10メガバイトまたは100メガバイト以上測定します。
Blowfishは、キーに依存するSボックス(4 kBテーブル)の多くのルックアップで機能するため、高速です。 Javaでは、配列アクセスがチェックされます(インデックスは配列の長さ内に収まる必要があります)。そのため、他の操作よりも比較的遅くなります。したがって、配列アクセスに重い暗号化アルゴリズムは、算術演算として表現されるアルゴリズム(典型的なケースはRC4)と比較してスローダウン要因を招きます。これは、mayが、JavaベースのBlowfishが(JavaベースのAESと比較して)CベースのBlowfish(比較してCベースのAES)。
最近のCPUには 特殊なAESオペコード があり、これは非常に高速なAES暗号化を意味します。純粋なJavaライブラリはこれらのオペコードを使用できませんが、Javaはネイティブコードを呼び出す可能性があります。ライブラリがネイティブコードを使用してAES-NIオペコードを呼び出す場合、 AES暗号化は必然的にスクリーマーになり、Blowfishは競合できなくなります。
最新のx86 CPUは、AES暗号化/復号化に ハードウェアアクセラレーション を提供します。これは JVMで有効 です。ソフトウェア実装のAESではBlowfishの方が高速かもしれませんが、ハードウェアアクセラレーションにより、はるかに高速になります。
ちなみに、この質問はここではなくスタックオーバーフローに関するものです。