3

コードに問題があります。

私がやろうとしているのは、ECB モードを使用してファイルを暗号化することです (つまり、次のブロックにチェーンせずにテキストのブロックを暗号化します)。

完全に機能することもありますが、機能しないこともあります。問題は、128 バイトのデータを暗号化し、129 バイトを書き込むときに発生します。初めてそれを行うまでは完全に機能しますが、その後、復号化は1バイトずれて、すべてが台無しになります。私がこれを知っているのは、うまくいかない場合、cipher (行 88、バイト配列) の長さが 128 ではなく 129 であり、ファイルに書き込まれることがわかるからです。

暗号化: testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest

出力: testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest(500 バイトのごちゃまぜデータ)

コード全体を添付しました。簡単に実行するために、暗号化の直後に標準出力に生成する復号化を有効にしました。

-k key (key.public と key.private を生成します) -e key.public -i input -o output (ファイル入力を暗号化して出力に保存し、そのファイルを読み取り、復号化して、標準出力)。

どんな助けでも大歓迎です!

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Scanner;
import java.io.*;
import java.util.List;
import java.util.Random;

public class RSA {


    public static void main(String[] args) throws UnsupportedEncodingException {
        List<String> list = Arrays.asList(args);
        if(list.contains("-h")) {
            System.out.println("Usage:");
            System.out.println("RSA -h - View command-line arguments.");
            System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
            System.out.println("RSA -e <key file>.public -i <input file> -o <output file> - Encrypt <input file> with key <key file>, store in <output file>.");
            System.out.println("RSA -d <key file>.private -i <input file> -o <output file> - Decrypt <input file> with key <key file>, store in <output file>.");
        } else if (list.contains("-k")) {
            String key_file = "";
            try {
                key_file = list.get(list.indexOf("-k") + 1);
                if(key_file.equals("-b")) {
                    System.out.println("Usage:");
                    System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
                    System.exit(1);
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Usage:");
                System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
                System.exit(1);
            }
            int bit_size = 0;
            if(!list.contains("-b")) {
                bit_size = 1024;
            } else {
                try {
                    bit_size = Integer.parseInt(list.get(list.indexOf("-b") + 1));
                } catch(ArrayIndexOutOfBoundsException e) {
                    System.out.println("Usage:");
                    System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
                    System.exit(1);
                }
            }

            generate_key(bit_size, key_file);

        } else if (list.contains("-e")) {
            //get input file and output file
            String input_file = "";
            String key_file = "";
            String output_file = "";
            try {
                input_file = list.get(list.indexOf("-i") + 1);
                output_file = list.get(list.indexOf("-o") + 1);
                key_file = list.get(list.indexOf("-e") + 1);
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Usage:");
                System.out.println("RSA -e <key file>.public -i <input file> -o <output file> - Encrypt <input file> with key <key file>, store in <output file>.");
                System.exit(1);
            }

            String public_key = read_file(key_file);
            String private_key = read_file("key.private");

            BigInteger public_modulus = new BigInteger(public_key.substring(1, public_key.indexOf(',')));
            BigInteger public_exponent = new BigInteger(public_key.substring(public_key.indexOf(',') + 1, public_key.length() - 1));

            byte[] file = read_bytes(input_file);
            byte[] cipher = new byte[128];
            byte[] decrypted = new byte[128];

            BigInteger d = new BigInteger(private_key.substring(1, private_key.indexOf(',')));
            BigInteger modulus = new BigInteger(private_key.substring(private_key.indexOf(',') + 1, private_key.length() - 1));

            write_file(output_file, "", false);
            int index = 0;
            while (index<file.length) {
                byte[] block = Arrays.copyOfRange(file, index, index+128);
                cipher = new BigInteger(block).modPow(public_exponent, public_modulus).toByteArray();
                append_bytes(output_file, cipher);
                index+=128;
            }

            byte[] encrypted = read_bytes(output_file);


            index = 0;
            while(index < encrypted.length) {
                byte[] block = Arrays.copyOfRange(encrypted, index, index+256);
                decrypted =  new BigInteger(block).modPow(d, modulus).toByteArray();
                System.out.println(new String(decrypted));
                index+= 256;
            }


        } else if (list.contains("-d")) {
            /*String input_file, output_file, key_file;
            input_file = output_file = key_file = "";

            try {
                input_file = list.get(list.indexOf("-i") + 1);
                output_file = list.get(list.indexOf("-o") + 1);
                key_file = list.get(list.indexOf("-d") + 1);
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Usage:");
                System.out.println("RSA -d <key file>.private -i <input file> -o <output file> - Decrypt <input file> with key <key file>, store in <output file>.");
                System.exit(1);
            }

            String private_key = read_file(key_file).toString();
            BigInteger d = new BigInteger(private_key.substring(1, private_key.indexOf(',')));
            BigInteger modulus = new BigInteger(private_key.substring(private_key.indexOf(',') + 1, private_key.length() - 1));

            byte[] encrypted = null;
            /* todo */

        } else {
            System.out.println("Usage:");
            System.out.println("RSA -h - View command-line arguments.");
            System.out.println("RSA -k <key file> -b <bit size> - Generate public/private keyfiles of size <bit size>.");
            System.out.println("RSA -e <key file>.public -i <input file> -o <output file> - Encrypt <input file> with key <key file>, store in <output file>.");
            System.out.println("RSA -d <key file>.private -i <input file> -o <output file> - Decrypt <input file> with key <key file>, store in <output file>.");
        }
    }

    private static void generate_key(int bit_size, String key_file) {
        BigInteger p = BigInteger.probablePrime(bit_size, new Random());
        BigInteger q = BigInteger.probablePrime(bit_size, new Random());

        BigInteger one = new BigInteger("1");
        BigInteger phi = new BigInteger("1");
        BigInteger e = new BigInteger("65537");

        boolean done = false;

        while(!done) {
            BigInteger temp = p.subtract(one);
            BigInteger temp2 = q.subtract(one);
            phi = (temp.multiply(temp2));
            if(phi.gcd(e).equals(one)) {
                done = true;
            } else {
                e = BigInteger.probablePrime(bit_size, new Random());
            }
        }

        BigInteger public_modulus = p.multiply(q);
        BigInteger public_exponent = e;
        BigInteger private_key = public_exponent.modInverse(phi); //d

        try {
            write_file(key_file + ".public", "(" + public_modulus + "," + e + ")", false);
            write_file(key_file + ".private", "(" + private_key.toString() + "," + public_modulus + ")", false);
        } catch (Exception ex) {
            System.out.println("Error creating key files.");
            System.exit(1);
        }

    }


    public static void write_bytes(String file_name, byte[] bytes) {
        try {
            FileOutputStream fos = new FileOutputStream(new File(file_name));
            fos.write(bytes);
            fos.close();
        } catch (IOException e) {
            System.out.println("Error writing bytes to file.");
            System.exit(1);
        }
    }

    public static String read_file(String file_name) {
        boolean is_key = false;
        if(file_name.contains(".public") || file_name.contains(".private"))
            is_key = true;

        Scanner sc = null;
        try {
            sc = new Scanner (new File(file_name));
        } catch (FileNotFoundException e) {
            System.out.println("Input file does not exist.");
            System.exit(1);
        }

        StringBuilder buf = new StringBuilder("");
        while (sc.hasNext ()) {
           buf.append (sc.nextLine());
           if(!is_key)
               buf.append("\n");
        }
        sc.close();
        return buf.toString();
    }

    public static byte[] read_bytes(String file_name) {
        Path path = Paths.get(file_name);
        byte[] encrypted = null;
        try {
            encrypted = Files.readAllBytes(path);
        } catch (IOException e) {
            System.out.println("Error reading bytes from " + file_name);
            System.exit(1);
        }
        return encrypted;
    }
    public static void append_bytes(String file_name, byte[] bytes) {
        try {
            OutputStream fos = new FileOutputStream(file_name, true);
            fos.write(bytes);
            fos.flush();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Error appending bytes to file.");
            System.exit(1);
        }
    }

    public static void write_file(String file_name, String message, boolean append) {
        try {
            FileWriter fstream = new FileWriter(file_name, append);
            BufferedWriter out = new BufferedWriter(fstream);
            out.write(message);
            out.close();
        } catch (Exception e){
            System.out.println("Error writing to file.");
            System.exit(1);
        }
    }
}
4

2 に答える 2

4

ECB は、ブロック暗号操作モードですRSAブロック暗号ではなく、公開鍵暗号方式です。

一般に、長いメッセージを RSA で直接暗号化することは意味がありません。むしろ、ハイブリッド暗号化を使用します。 AESのような対称暗号のランダム キーを選択し、対称暗号でメッセージを暗号化し、対称キーを RSA で暗号化します。

また、 RSA でキーを暗号化する場合は、 OAEPなどの適切なパディング スキームを使用することを忘れないでください。パディングされていない「教科書 RSA」は安全ではありません。(または、パディングを必要としないRSA-KEM のようなスキームを使用します。) AES にも ECB モードを使用しないでください。CBC や CTR のような意味的に安全なモードを使用するか、認証済み暗号化モードを使用することをお勧めします。

于 2013-03-02T16:42:51.103 に答える
0

問題は「BigInteger.toByteArray()」です。このバイト配列は後処理する必要があります。配列の最初の要素は符号ビットを持ち、他のバイトは符号なしで扱われます。正数の最上位ビットがビット 7 にある場合、このメソッドは先頭に 0 を追加して正符号を表します。この 0 バイトを削除すると、出力のブロック サイズは一定になります。逆に、配列から正の BigInteger を構築する場合、先行ゼロ ビット 7 が必要です。

鍵の生成について: q、p は通常半分のビット サイズを持ち、「n = p*q」は ウィキペディアの RSA 鍵の生成を参照してください。

セキュリティについて: 前述のとおり、「Textbook RSA」はストリーミングに対して安全ではありません。最低限必要な変更は、各ブロックにランダムなバイト「salt」を追加することです。一般的な RSA 実装では、このためにブロック サイズの約 25% が予約されています。また、操作モードCBCに切り替えることをお勧めします。

受け入れに関して: すべての Java ランタイム プロバイダーとバージョンで利用できる移植可能な暗号化アルゴリズムはほとんどなく、各バリアントは継続的に開発され、寿命が限られています。また、実装は隠され、バックドアがある可能性があります。因数分解問題の難しさから、自力で行うことは移植性、追跡可能性、安全性が高く、個々の改変攻撃者にはわかりません。最後に、パフォーマンスの欠如はセキュリティ要因です。たとえば、パスワードに依存するハッシュを導入すると、ブルート フォース パスワード検索は時間内に成功しません。

于 2021-07-17T18:55:53.680 に答える