web-dev-qa-db-ja.com

AES暗号化はモードを使用する必要がありますか?

現在、Java暗号化アーキテクチャを使用したファイル暗号化プログラムに取り組んでいます。

私の計画は、各ファイルが異なるAESキーを持つ暗号化されたファイルをいくつか持つことです。暗号化ファイルを追跡するために、各暗号化ファイルのエントリを格納するメタデータファイルも含めます。値はプレーンテキストファイル名、暗号化ファイル名、AESキーです。

次に、メタデータファイルは、ユーザーのパスワードから派生したAESキーを使用して暗号化されます。

私の質問は、モードを実装する必要がありますか?暗号化されたメタデータにすべてのパスワードを保存することは許容できる慣行だと思いますか?

これが私が参照してきたコードです:

public class PasswordBasedEncryption {

PBEKeySpec pbeKeySpec;
PBEParameterSpec pbeParamSpec;
SecretKeyFactory keyFac;

// Salt
byte[] salt = {
        (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
        (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
// Iteration count
int count = 65536;
int keySize = 128;

Cipher pbeCipher;
SecretKey pbeKey;
FileInputStream fis;
FileOutputStream fos;

/**
 * constructor given a master password
 * Use password based derivation function II to make AES key.
 * used only for the metadata file encryption
 * @param password
 */
public PasswordBasedEncryption(char[] password){
    try{
        keyFac = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        pbeKeySpec = new PBEKeySpec(password, salt, count, keySize);
        SecretKey tempKey = keyFac.generateSecret(pbeKeySpec);
        pbeKey = new SecretKeySpec(tempKey.getEncoded(), "AES");
        pbeCipher = Cipher.getInstance("AES");
    }
    catch (Exception e){e.printStackTrace();}
}
/**
 * constructor given a generated AES key
 * each file has its own AES key to avoid known text attacks
 * @param key
 */
public PasswordBasedEncryption(SecretKey key){
    try{
        pbeKey = key;
    }
    catch (Exception e){e.printStackTrace();}
}

public void encrypt(String filePath, String cipherName){
    try{
        File clearFile = new File(filePath);
        fis = new FileInputStream(clearFile);

        pbeCipher = Cipher.getInstance("AES");
        pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey);

        CipherInputStream cis = new CipherInputStream(fis, pbeCipher);          
        File cipherFile = new File(Path.TEMP + cipherName);
        fos = new FileOutputStream(cipherFile);
        int read;
        while((read = cis.read())!=-1)
        {
            fos.write((char)read);
            fos.flush();
        } 
        cis.close();
        fos.close();
        fis.close();
    }
    catch(Exception e ){e.printStackTrace();}
}

public void decrypt(String cipherName, String filePath){
    try{

        fis = new FileInputStream(Path.TEMP + cipherName);          
        File clearFile = new File(filePath);
        fos = new FileOutputStream(clearFile);

        pbeCipher = Cipher.getInstance("AES");
        pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey);
        CipherOutputStream cos = new CipherOutputStream(fos, pbeCipher);            
        int read;
        while((read = fis.read())!=-1)
        {
            cos.write(read);
            cos.flush();
        } 
        cos.close();
        fis.close();
        fos.close();
    }
    catch(Exception e ){e.printStackTrace();}
}


/**
 * Generate secret password used each time a new file needs encrypting
 * @return
 */
public static SecretKey genPass(){
    KeyGenerator keyGen;
    try {
        keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128);
        return keyGen.generateKey();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}
}
3
John

[〜#〜] aes [〜#〜]ブロック暗号です:入力としてキーを受け取り、oneのブロックは正確に16バイトで、16バイトの別のブロックを出力します。それがAES自体の機能です。

したがって、単一の16バイトブロックではないバイトシーケンスを暗号化する場合は、「 操作モード 」を使用する必要があります。そして、それはあなたがすでにあなたのコードでやっていることです。コードで実際に指定しなかっただけで、Javaから1つ選択させます。残念ながら、デフォルトはECBで、これはひどくて弱いです。詳細は このドキュメントを参照してください これには以下が含まれます。

たとえば、SunJCEプロバイダーは、デフォルトモードとしてECBを使用し、DES、DES-EDE、およびBlowfish暗号のデフォルトパディング方式としてPKCS5Paddingを使用します。

(ここではAESについての言葉はありません。)

したがって、いずれにしても:

  • あなたは自分が何をしているかを理解しなければなりません。セキュリティをテストすることはできないため、特に暗号化を使用して安全なコードを作成する唯一の方法は、内部で何が発生するかについて徹底的かつ詳細に理解することです。

  • あなたはあなたがしていることを正確に指定しなければなりません。あなたの言語に不適切に定義されたデフォルト値を選択させないでください。

  • あなた自身でそれをしてはいけません。安全な暗号コードの作成は、開発で最も困難な作業の1つです。正確に作成したかどうかを知る方法がないためです(ただし、経験上、「いいえ、不十分に行われており、弱い」という答えはほとんど常に当てはまります)。

10
Tom Leek

一般的に、コードに問題があるようです。まったく安全ではなく、例外を破棄しますが、セキュリティ関連のアプリケーションには適していません。

私はそれが何らかの商業プロジェクトのためではなく、あなたが何かを学ぶために(そしてただ)学ぶための私的プロジェクトだと思います。それはまったく問題ありません。ただし、安全なコードの記述に慣れるまで、これを顧客(これには友達も含む)に出荷しないことをお勧めします。


"AES/CBC/PKCS5Padding"のように、暗号のパディングとモードを指定する必要があります。モードとパディングを指定しないと、実装に依存する問題が発生する可能性があります(別のモードを使用する別のJVMが原因でファイルを復号化できないなど)。また、ECBのようなモードは一部の攻撃から保護されないことに注意してください。この暗号化されたイメージを参照してください:

ECB-Encrypted Tux

http: //www.isc.tamu.edu/~lewing/linux/

詳細については、 ブロック暗号モードに関するWikipediaの記事 を参照してください。それで、私はあなたのアプリケーションのためにCBCに行きます。

3
dst

まあ、いいえ、そうではないと思いますが、その場合、最初のブロックを超えて、指定されたキーで暗号化する方法はありません。これは、入力なしで、または暗号化アルゴリズムなしで何かを暗号化できるかどうかを尋ねるようなものです。モードは、各ブロックのキーがどのように導出され、暗号化が実際に行われるかです。これは暗号化の重要な部分であり、「モードを持たない」ことやアルゴリズムを機能させることはできません。

暗号化されたメタデータにAESファイルキーを保存することに関して。すべてに同じキーを使用するよりもセキュリティが大幅に向上するわけではありませんが、問題はありません。メタデータファイルは基本的にキーリングです。したがって、1つのファイルが失われてクラックされても、残りのファイルは危険にさらされません。宇宙の熱死なので、あまり多くは得られません...

0
AJ Henderson