暗号化 - Sizuha/devdog GitHub Wiki
- AESの前の暗号化アルゴリズムで、8 bytes ブロック単位で暗号化。
- 暗号化後のByte数もは8の倍数になる。
- AESよりセキュリティ的に弱いので、3回重ねるTriple DES(3DES、DESede)で使う
- 暗号鍵:24 bytes
- AESがDESの発展型なので、基本的にDESと同じ
- 128bit(16 bytes)ブロック単位で暗号化するので、暗号化後のByte数も16の倍数になる。
- 暗号鍵:16 bytes
- ECB:各ブロックを同じ鍵を使って独立して暗号化
- CBC:各ブロックの暗号化に前のブロックの暗号文を使用するため、初期化ベクトル(IV)というものが必要(※ ECBはセキュリティ的にあまりお勧めしない)
- 普通は、同じ原文を同じ暗号鍵で暗号化すると、同じ結果が出る。
- IV:最初に入れるデータブロックで、同じ原文で同じ鍵でもIVが変わると結果も変わる。 (暗号化後のBytes数には影響なし)
- IVは暗号化するブロックの長さ同じBytes数にすること。 例)AES128 => IV: 128 bit (16 bytes)
- ブロック単位で暗号化する為、原文の長さもブロックのByte数の倍数にしないといけない。 例)AES128の場合: ”1234567890123456” (16 bytes) -> OK、 "1234567890" (10 bytes) -> NG
- Paddingは原文に足りないByte分を埋める
- PKCS5/PKCS7 などがある
import static org.junit.Assert.*;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class CryptoUtilTest {
// 暗号化
public static byte[] encryptAES(byte[] plainBytes, byte[] key, byte[] iv) {
try {
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivSpec = new IvParameterSpec(iv);
final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(plainBytes);
} catch (Exception e) {
return null;
}
}
// 復号化
public static byte[] decryptAES(byte[] encryptedBytes, byte[] key, byte[] iv) {
try {
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivSpec = new IvParameterSpec(iv);
final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(encryptedBytes);
} catch (Exception e) {
return null;
}
}
@Test
public void testAES() {
// 原文
final String orgText = "AES-SAMPLE";
// 暗号鍵
final byte[] key = "1234567890123456".getBytes(StandardCharsets.UTF_8); // 16 bytes
// 初期化ベクトル
final byte[] iv = "1234567890abcdef".getBytes(StandardCharsets.UTF_8); // 16 bytes
final byte[] bytes = orgText.getBytes(StandardCharsets.UTF_8);
final byte[] encoded = encryptAES(bytes, key, iv);
final byte[] decoded = decryptAES(encoded, key, iv);
final String decodedText = new String(decoded, StandardCharsets.UTF_8);
assertEquals(orgText, decodedText);
}
}
- 暗号化の鍵と復号化の鍵が別
- 大きな数の素因数分解の計算が難しいことを利用
例)4261 x 8521 = 36307981
素数2つの掛け算は簡単、しかし、36307981を素因数分解するのは難度が高い
※参考:https://it-trend.jp/encryption/article/64-0056
Key Size(bit) | 暗号化できるBytes | 暗号化後のBytes |
---|---|---|
512 | 22 | 64 |
1024 | 86 | 128 |
2048 | 214 | 256 |
※Android/Javaで確認した結果
公開鍵と秘密鍵のペアを生成して使う
final KeyPairGenerator kpg;
try {
kpg = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
return null;
}
kpg.initialize(1024); // 鍵の大きさ(bits)
final KeyPair kp = kpg.genKeyPair(); // 鍵のペアを生成
final PublicKey pubKey = kp.getPublic(); // 公開鍵
final PrivateKey priKey = kp.getPrivate(); // 秘密鍵
final byte[] pubKeyBytes = pubKey.getEncoded(); // 公開鍵のByte配列
// Byte配列からPublicKey作成
public static RSAPublicKey createRsaPublicKey(@NonNull byte[] pubKeyBytes) {
final X509EncodedKeySpec spec = new X509EncodedKeySpec(pubKeyBytes);
try {
final KeyFactory kf = KeyFactory.getInstance("RSA");
return (RSAPublicKey) kf.generatePublic(spec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
return null;
}
}
// 公開鍵で暗号化
public static byte[] encryptRSA(@NonNull byte[] plainBytes, @NonNull PublicKey rsaPublicKey) {
try {
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, rsaPublicKey);
return cipher.doFinal(plainBytes);
} catch (Exception e) {
return null;
}
}
public static byte[] decryptRSA(@NonNull byte[] encryptedBytes, @NonNull PrivateKey privateKey) {
try {
final Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encryptedBytes);
} catch (Exception e) {
return null;
}
}
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Sha1Hex {
public String makeSHA1Hash(String input) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA1");
md.reset();
byte[] buffer = input.getBytes();
md.update(buffer);
byte[] digest = md.digest();
String hexStr = "";
for (int i = 0; i < digest.length; i++) {
hexStr += Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return hexStr;
}
}