Java – ハイブリッド暗号の例

ハイブリッド暗号は、大量のデータ(非対称暗号)と安全ではないが高速の暗号(対称暗号)との間の安全な、しかし遅い暗号化の間の銀の裏地です。 Hybrid Cryptographyは、ワン・キーの暗号化と復号化の速度と、公開鍵と秘密鍵のペアが提供するセキュリティーを組み合わせることで、高度に安全な暗号化タイプとみなされます。
ハイブリッド暗号化の最も一般的な方法は、送信者の秘密鍵または受信者の公開鍵で暗号化される対称鍵を使用してデータを暗号化することです。受信者は、まず対応する非対称キーを使用して対称鍵を復号し、次にその対称鍵を使用して受信したデータを復号化する必要があります。この例は、次のことを明確にするのに役立ちます。
既に公開鍵を交換している2人のユーザー、AliceとBobとのシナリオを想像してみてください。 Aliceは、Bobに “confidential.txt”というテキストファイルを送信したいと考えています。メッセージを暗号化する手順は次のとおりです。
-
強力なアルゴリズムを使用して新しい対称鍵を生成する
-
手順1のキーを使用して「confidential.txt」を暗号化します.
-
Bobの公開鍵を使用してステップ1からの鍵を暗号化する
-
暗号化されたテキストとキーの両方をBobに送信します.
Bobは2つのファイルを受信します。それらの解読に続く手順は次のとおりです。
-
自分の秘密鍵を使用して受信した鍵を復号化する
-
手順1で取得したキーを使用して受け取ったテキストを
解読
以下のコードのプロセスは、プロセスを理解し、学習者を楽にするために、別々のファイルに分割されています。
1.プロジェクトディレクトリ

2.アリスとボブのための鍵を生成する
プラットフォームに応じて公開鍵と秘密鍵のペアを生成するには、いくつかの方法があります。この例では、アリス用とボブ用の2つのペアをjavaを使用して作成します。この例で使用する暗号アルゴリズムはRSAです。
GenerateKeys.java
package com.techfou.keypair;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
public class GenerateKeys {
private KeyPairGenerator keyGen;
private KeyPair pair;
private PrivateKey privateKey;
private PublicKey publicKey;
public GenerateKeys(int keylength)
throws NoSuchAlgorithmException, NoSuchProviderException {
this.keyGen = KeyPairGenerator.getInstance("RSA");
this.keyGen.initialize(keylength);
}
public void createKeys() {
this.pair = this.keyGen.generateKeyPair();
this.privateKey = pair.getPrivate();
this.publicKey = pair.getPublic();
}
public PrivateKey getPrivateKey() {
return this.privateKey;
}
public PublicKey getPublicKey() {
return this.publicKey;
}
public void writeToFile(String path, byte[]key) throws IOException {
File f = new File(path);
f.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(f);
fos.write(key);
fos.flush();
fos.close();
}
public static void main(String[]args)
throws NoSuchAlgorithmException, NoSuchProviderException, IOException {
GenerateKeys gk__Alice;
GenerateKeys gk__Bob;
gk__Alice = new GenerateKeys(1024);
gk__Alice.createKeys();
gk__Alice.writeToFile("KeyPair/publicKey__Alice", gk__Alice.getPublicKey().getEncoded());
gk__Alice.writeToFile("KeyPair/privateKey__Alice", gk__Alice.getPrivateKey().getEncoded());
gk__Bob = new GenerateKeys(1024);
gk__Bob.createKeys();
gk__Bob.writeToFile("KeyPair/publicKey__Bob", gk__Bob.getPublicKey().getEncoded());
gk__Bob.writeToFile("KeyPair/privateKey__Bob", gk__Bob.getPrivateKey().getEncoded());
}
}
出力:

3.アリスが対称キーを生成する
以下のコードでは、対称キーを生成することができます。コードは `SecureRandom`を使用してキーにランダム性を追加します。 `SecureRandom`の詳細については、
Java – 強い乱数を作成する方法
を参照してください。
コンストラクタは、キーが保存されるディレクトリへのパス、キーの長さ、およびキーの作成に使用されるアルゴリズムによって初期化されます。各アルゴリズムのキーの長さの詳細は、https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html[暗号アルゴリズムの制限のインポート]を参照してください。
この例では、スピードとセキュリティの間にシルバーライニングと見なされるため、AESを使用しています。暗号化アルゴリズムの詳細については、http://www.cs.wustl.edu/~jain/cse567-06/ftp/encryption
perf/#2
5[データ暗号化アルゴリズムのパフォーマンス解析:2.5比較アルゴリズム]を参照してください。
GenerateSymmetricKey.java
package com.techfou.onekey;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class GenerateSymmetricKey {
private SecretKeySpec secretKey;
public GenerateSymmetricKey(int length, String algorithm)
throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException {
SecureRandom rnd = new SecureRandom();
byte[]key = new byte[length];
rnd.nextBytes(key);
this.secretKey = new SecretKeySpec(key, algorithm);
}
public SecretKeySpec getKey(){
return this.secretKey;
}
public void writeToFile(String path, byte[]key) throws IOException {
File f = new File(path);
f.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(f);
fos.write(key);
fos.flush();
fos.close();
}
public static void main(String[]args)
throws NoSuchAlgorithmException, NoSuchPaddingException, IOException {
GenerateSymmetricKey genSK = new GenerateSymmetricKey(16, "AES");
genSK.writeToFile("OneKey/secretKey", genSK.getKey().getEncoded());
}
}
出力:

4.アリスは彼女のメッセージを書きます

5.アリスがデータを暗号化する
5.1
StartEncryption`クラスには、ファイルから対応するキーを構築するために使用される3つのメソッド
getPrivate()
、
getPublic()
、
getSecretKey()
が含まれています。 mainメソッドでは、暗号化のために呼び出す2つのクラスに使用する必要がある `Fileオブジェクト`を構築します。 `EncryptData`と
EncryptKey`です。
StartEncryption.java
package com.mkyong.hybrid.encrypt;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class StartEncryption {
public PrivateKey getPrivate(String filename, String algorithm) throws Exception {
byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePrivate(spec);
}
public PublicKey getPublic(String filename, String algorithm) throws Exception {
byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePublic(spec);
}
public SecretKeySpec getSecretKey(String filename, String algorithm) throws IOException{
byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
return new SecretKeySpec(keyBytes, algorithm);
}
public static void main(String[]args)
throws IOException, GeneralSecurityException, Exception{
StartEncryption startEnc = new StartEncryption();
File originalKeyFile = new File("OneKey/secretKey");
File encryptedKeyFile = new File("EncryptedFiles/encryptedSecretKey");
new EncryptKey(startEnc.getPublic("KeyPair/publicKey__Bob", "RSA"),
originalKeyFile, encryptedKeyFile, "RSA");
File originalFile = new File("confidential.txt");
File encryptedFile = new File("EncryptedFiles/encryptedFile");
new EncryptData(originalFile, encryptedFile,
startEnc.getSecretKey("OneKey/secretKey", "AES"), "AES");
}
}
5.2
EncryptData`コンストラクタはパラメータとして2つの
File`オブジェクトを受け取ります(最初は暗号化したいファイル、2つ目は出力ファイルです)。暗号化に使用する対称鍵である
SecretKeySpec`オブジェクト`Cipher`に使用するアルゴリズムの名前を
String`にします。
EncryptData.java
package com.mkyong.hybrid.encrypt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.SecretKeySpec;
public class EncryptData {
private Cipher cipher;
public EncryptData(File originalFile, File encrypted, SecretKeySpec secretKey, String cipherAlgorithm)
throws IOException, GeneralSecurityException{
this.cipher = Cipher.getInstance(cipherAlgorithm);
encryptFile(getFileInBytes(originalFile), encrypted, secretKey);
}
public void encryptFile(byte[]input, File output, SecretKeySpec key)
throws IOException, GeneralSecurityException {
this.cipher.init(Cipher.ENCRYPT__MODE, key);
writeToFile(output, this.cipher.doFinal(input));
}
private void writeToFile(File output, byte[]toWrite)
throws IllegalBlockSizeException, BadPaddingException, IOException{
output.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(output);
fos.write(toWrite);
fos.flush();
fos.close();
System.out.println("The file was successfully encrypted and stored in: " + output.getPath());
}
public byte[]getFileInBytes(File f) throws IOException{
FileInputStream fis = new FileInputStream(f);
byte[]fbytes = new byte[(int) f.length()];
fis.read(fbytes);
fis.close();
return fbytes;
}
}
5.3
EncryptKey`コンストラクタは、暗号化に使用される
PublicKey`、2つの
File`オブジェクト(最初は対称キーを含むファイル、もう1つは出力ファイルです)と
String` `Cipher`に使用するアルゴリズムの名前で置き換えます。
EncryptKey.java
package com.mkyong.hybrid.encrypt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
public class EncryptKey {
private Cipher cipher;
public EncryptKey(PublicKey key, File originalKeyFile, File encryptedKeyFile, String cipherAlgorithm)
throws IOException, GeneralSecurityException{
this.cipher = Cipher.getInstance(cipherAlgorithm);
encryptFile(getFileInBytes(originalKeyFile), encryptedKeyFile, key);
}
public void encryptFile(byte[]input, File output, PublicKey key)
throws IOException, GeneralSecurityException {
this.cipher.init(Cipher.ENCRYPT__MODE, key);
writeToFile(output, this.cipher.doFinal(input));
}
private void writeToFile(File output, byte[]toWrite)
throws IllegalBlockSizeException, BadPaddingException, IOException{
output.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(output);
fos.write(toWrite);
fos.flush();
fos.close();
System.out.println("The key was successfully encrypted and stored in: " + output.getPath());
}
public byte[]getFileInBytes(File f) throws IOException{
FileInputStream fis = new FileInputStream(f);
byte[]fbytes = new byte[(int) f.length()];
fis.read(fbytes);
fis.close();
return fbytes;
}
}
出力:
The key was successfully encrypted and stored in: EncryptedFiles\encryptedSecretKey The file was successfully encrypted and stored in: EncryptedFiles\encryptedFile

6.ボブはデータを受信し、それらを復号化する.
6.1
StartDecryption`クラスはファイルから対応するキーを構築するのに使われる
getPrivate()
、
getPublic()
、
getSecretKey()
の3つのメソッドを含みます。 mainメソッドでは、復号化のために呼び出す2つのクラスのために使用する必要がある `File`オブジェクトを構築します。 `DecryptData`と
DecryptKey`です。
StartDecryption.java
package com.mkyong.hybrid.decrypt;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class StartDecryption {
public PrivateKey getPrivate(String filename, String algorithm) throws Exception {
byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePrivate(spec);
}
public PublicKey getPublic(String filename, String algorithm) throws Exception {
byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance(algorithm);
return kf.generatePublic(spec);
}
public SecretKeySpec getSecretKey(String filename, String algorithm) throws IOException{
byte[]keyBytes = Files.readAllBytes(new File(filename).toPath());
return new SecretKeySpec(keyBytes, algorithm);
}
public static void main(String[]args) throws IOException, GeneralSecurityException, Exception{
StartDecryption startEnc = new StartDecryption();
File encryptedKeyReceived = new File("EncryptedFiles/encryptedSecretKey");
File decreptedKeyFile = new File("DecryptedFiles/SecretKey");
new DecryptKey(startEnc.getPrivate("KeyPair/privateKey__Bob", "RSA"),
encryptedKeyReceived, decreptedKeyFile, "RSA");
File encryptedFileReceived = new File("EncryptedFiles/encryptedFile");
File decryptedFile = new File("DecryptedFiles/decryptedFile");
new DecryptData(encryptedFileReceived, decryptedFile,
startEnc.getSecretKey("DecryptedFiles/SecretKey", "AES"), "AES");
}
}
6.2 DecryptKeyコンストラクタは、解読に使用される
PrivateKey
、2つの` File`オブジェクト(最初は暗号化キー、2番目は出力ファイル)と `私たちが `Cipher`に使うアルゴリズムです。
DecryptKey.java
package com.mkyong.hybrid.decrypt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
public class DecryptKey {
private Cipher cipher;
public DecryptKey(PrivateKey privateKey, File encryptedKeyReceived, File decreptedKeyFile, String algorithm)
throws IOException, GeneralSecurityException {
this.cipher = Cipher.getInstance(algorithm);
decryptFile(getFileInBytes(encryptedKeyReceived), decreptedKeyFile, privateKey);
}
public void decryptFile(byte[]input, File output, PrivateKey key)
throws IOException, GeneralSecurityException {
this.cipher.init(Cipher.DECRYPT__MODE, key);
writeToFile(output, this.cipher.doFinal(input));
}
private void writeToFile(File output, byte[]toWrite)
throws IllegalBlockSizeException, BadPaddingException, IOException{
output.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(output);
fos.write(toWrite);
fos.flush();
fos.close();
}
public byte[]getFileInBytes(File f) throws IOException{
FileInputStream fis = new FileInputStream(f);
byte[]fbytes = new byte[(int) f.length()];
fis.read(fbytes);
fis.close();
return fbytes;
}
}
6.3 DecryptDataコンストラクタは、パラメータとして2つの
File`オブジェクト(最初は暗号化されたファイル、2つ目は出力ファイルです)、
SecretKeySpec`オブジェクト(復号化に使用する対称鍵)、 `String `をCipherに使用するアルゴリズムの名前で置き換えます。
DecryptData.java
package com.mkyong.hybrid.decrypt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.SecretKeySpec;
public class DecryptData {
private Cipher cipher;
public DecryptData(File encryptedFileReceived, File decryptedFile, SecretKeySpec secretKey, String algorithm)
throws IOException, GeneralSecurityException {
this.cipher = Cipher.getInstance(algorithm);
decryptFile(getFileInBytes(encryptedFileReceived), decryptedFile, secretKey);
}
public void decryptFile(byte[]input, File output, SecretKeySpec key)
throws IOException, GeneralSecurityException {
this.cipher.init(Cipher.DECRYPT__MODE, key);
writeToFile(output, this.cipher.doFinal(input));
}
private void writeToFile(File output, byte[]toWrite)
throws IllegalBlockSizeException, BadPaddingException, IOException{
output.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(output);
fos.write(toWrite);
fos.flush();
fos.close();
System.out.println("The file was successfully decrypted. You can view it in: " + output.getPath());
}
public byte[]getFileInBytes(File f) throws IOException{
FileInputStream fis = new FileInputStream(f);
byte[]fbytes = new byte[(int) f.length()];
fis.read(fbytes);
fis.close();
return fbytes;
}
}
出力:
The file was successfully decrypted. You can view it in: DecryptedFiles\decryptedFile

ソースコードをダウンロードする
ダウンロード – リンク://wp-content/uploads/2016/11/HybridCryptographyExample.zip[HybridCryptographyExample.zip](11 KB)
参考文献
暗号アルゴリズム]。
http://www.ijcscn.com/Documents/Volumes/vol5issue1/ijcscn2015050103.pdf
[comparative
非対称鍵暗号アルゴリズムの研究]。
https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#KeyPairGenerator
[KeyPairGenerator
暗号アルゴリズムの限界]。
https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html
[Cipher
アルゴリズム]
暗号化
リンク://tag/encrypt-file/[暗号化
ファイル]リンク://タグ/暗号化/[暗号化]リンク://タグ/java-security/[java
セキュリティ]リンク://タグ/公開鍵/[公開鍵]