3

Java で 3DES 暗号化を必要とするプロジェクトに取り組んでいます。問題は、「0123456789ABCDEF0123456789ABCDEF」のような 128 ビットの 16 進キーが提供されてきた (そして今後も提供され続ける) ことです。バイトへの変換は問題ありません。ただし、問題は、Java Cryptographic Extensions API がこのキーが無効であると言ってチョークすることです。各バイトの MSB は単なるパリティ ビットであることがわかったので、JCE は私がそれらを削除することを期待しています (または私はそう思います)。しかし、.NET では、提供されたキーを指定することができ、問題なく暗号化/復号化を静かに処理します。

提供された種類のキーから JCE が期待する種類のキーを生成する方法はありますか?

JCE では DES 暗号化に 8 バイトのキーを指定できることがわかったので、提供されたキーの半分を使用して 3DES を DES EDE として実装してみました。ただし、.NET ではまだ一貫性のない結果が得られます。

Javaコードは次のとおりです。

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;

public class Main{
    public static void main(String[] args) throws Exception {
        byte [] plain = "I eat fish every day".getBytes("utf-8");

        byte [] keyBytes = new byte [] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00
            };

        byte [] key2Bytes = new byte [] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0  }; // actual keys replaced with dummies.

        SecretKey keySpec = new SecretKeySpec(keyBytes, "DES");
        SecretKey keySpec2 = new SecretKeySpec(key2Bytes, "DES");

        IvParameterSpec iv = new IvParameterSpec(new byte[8]);

        Cipher e_cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");

        e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec2, iv);

        byte [] cipherText = e_cipher.doFinal(plain);
        cipherText = cipher.doFinal(cipherText);
        cipherText = e_cipher.doFinal(cipherText);

        System.out.println("Ciphertext: " + new sun.misc.BASE64Encoder().encode(cipherText));
    }
}

.NET コードは次のとおりです。

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace EncryptionDemo
{
    class Program
    {
    public static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        // TODO: Implement Functionality Here
        var plainBytes = Encoding.UTF8.GetBytes("I eat fish every day");
        var keyBytes = new byte [] { 0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00,
         0x00, 0x00, 0x00, 0x00,
         0x00,  0x00, 0x00, 0x00  };

        var tripleDES = TripleDESCryptoServiceProvider.Create();
        var transform = tripleDES.CreateEncryptor(keyBytes, new byte [8]);

        var memStream = new MemoryStream();
        var cStream = new CryptoStream(memStream, transform, CryptoStreamMode.Write);

        cStream.Write(plainBytes, 0, plainBytes.Length);
        cStream.FlushFinalBlock();

        //memStream.Position = 0;
        var cipherBytes = memStream.ToArray();

        Console.WriteLine("Ciphertext: " + Convert.ToBase64String(cipherBytes));

        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
    }
}

どちらも異なる出力を生成します (Base64 文字列の一部の文字は同じです)

4

3 に答える 3

4

3DES キーの長さは 192 ビットです。

どのようにSecretKeyインスタンスを作成していますか? どのようなエラー メッセージが表示されますか?


あなたの質問のJavaコードは、「トリプルDES」ではなく、DESを使用しています。アルゴリズム名は"DESede/CBC/PKCS5Padding". あなたの答えのコードは、プロバイダーを切り替えたからではなく、アルゴリズムが正しいために機能する可能性があります。Java 6 の SunJCE プロバイダは、128 ビット キーを受け入れます (そしてキーイング オプション 2 を使用します)。古いバージョンについてはわかりません。

于 2010-12-14T06:19:15.737 に答える
1

jPOSプロジェクトでは、この問題は常にシングルレングス(8バイト)またはトリプルレングス(24バイト)のキーを使用することで回避されます。明確な倍長キー(バイト単位)がAAAAAAAABBBBBBBBであるとします。これまで見てきたjPOSプロジェクトのJCEを使用するすべてのコードは、最初の8バイトをクリアキーに再度追加するため、AAAAAAAABBBBBBBBAAAAAAAAのように3倍の長さのキーになります。@ericksonが述べたように、192ビット長であるため、SunプロバイダーはSecreKeySpecを作成するためにこの資料を受け入れているようです。

于 2011-03-15T16:01:04.633 に答える
1

Sun プロバイダーは 16 バイトの 3DES キーを受け入れませんが、BouncyCastle プロバイダーは受け入れます。私はちょうどそれを試してみて、それは魔法のように動作します - それは.NETコードと同じ出力を生成します!

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Main{
    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        byte [] plain = "I eat fish every day".getBytes("utf-8");

        byte [] keyBytes = new byte [] { (byte) 0xC1, (byte) 0x57, (byte) 0x45, (byte) 0x08,
            (byte) 0x85, (byte) 0x02, (byte) 0xB0, (byte) 0xD3,
            (byte) 0xA2, (byte) 0xEF, (byte) 0x68, (byte) 0x43,
            (byte) 0x5E, (byte) 0xE6, (byte) 0xD0, (byte) 0x75 };


        SecretKey keySpec = new SecretKeySpec(keyBytes, "DESede");

        IvParameterSpec iv = new IvParameterSpec(new byte[8]);

        Cipher e_cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding", "BC");

        e_cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

        byte [] cipherText = e_cipher.doFinal(plain);

        System.out.println("Ciphertext: " + new sun.misc.BASE64Encoder().encode(cipherText));
    }
}
于 2010-12-14T08:07:47.737 に答える