Java Language
RSA 암호화
수색…
OAEP와 GCM으로 구성된 하이브리드 암호 시스템을 사용한 예
다음 예는 기본 매개 변수 크기와 128 비트의 AES 키 크기를 사용하여 AES GCM과 OAEP로 구성된 하이브리드 암호화 시스템 을 사용하여 데이터를 암호화합니다.
OAEP는 PKCS # 1 v1.5 패딩보다 패딩 오라클 공격에 덜 취약합니다. GCM은 패딩 오라클 공격으로부터 보호됩니다.
해독은 먼저 캡슐화 된 키의 길이를 검색 한 다음 캡슐화 된 키를 검색하여 수행 할 수 있습니다. 캡슐화 된 키는 공개 키와 키 쌍을 이루는 RSA 개인 키를 사용하여 해독 할 수 있습니다. 그런 다음 AES / GCM으로 암호화 된 암호문을 원래의 일반 텍스트로 해독 할 수 있습니다.
프로토콜은 다음과 같이 구성됩니다.
- 랩 된 키의 길이 필드 (
RSAPrivateKey
는getKeySize()
메소드를getKeySize()
). - 랩 된 / 캡슐화 된 키. RSA 키 사이즈와 같은 사이즈의 바이트.
- GCM 암호문 및 128 비트 인증 태그 (Java에 의해 자동으로 추가됨).
노트:
- 이 코드를 올바르게 사용하려면 적어도 2048 비트의 RSA 키를 제공해야합니다. 더 크면 좋습니다 (그러나 암호 해독 중에 특히 느립니다).
- AES-256을 사용하려면 무제한 암호화 정책 파일을 먼저 설치해야합니다.
- 자체 프로토콜을 만드는 대신 Cryptographic Message Syntax (CMS / PKCS # 7) 또는 PGP와 같은 컨테이너 형식을 사용할 수 있습니다.
여기 예제가 있습니다 :
/**
* Encrypts the data using a hybrid crypto-system which uses GCM to encrypt the data and OAEP to encrypt the AES key.
* The key size of the AES encryption will be 128 bit.
* All the default parameter choices are used for OAEP and GCM.
*
* @param publicKey the RSA public key used to wrap the AES key
* @param plaintext the plaintext to be encrypted, not altered
* @return the ciphertext
* @throws InvalidKeyException if the key is not an RSA public key
* @throws NullPointerException if the plaintext is null
*/
public static byte[] encryptData(PublicKey publicKey, byte[] plaintext)
throws InvalidKeyException, NullPointerException {
// --- create the RSA OAEP cipher ---
Cipher oaep;
try {
// SHA-1 is the default and not vulnerable in this setting
// use OAEPParameterSpec to configure more than just the hash
oaep = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for RSA cipher (mandatory algorithm for runtimes)", e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for OAEP padding (present in the standard Java runtime sinze XX)", e);
}
oaep.init(Cipher.WRAP_MODE, publicKey);
// --- wrap the plaintext in a buffer
// will throw NullPointerException if plaintext is null
ByteBuffer plaintextBuffer = ByteBuffer.wrap(plaintext);
// --- generate a new AES secret key ---
KeyGenerator aesKeyGenerator;
try {
aesKeyGenerator = KeyGenerator.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES key generator (mandatory algorithm for runtimes)", e);
}
// for AES-192 and 256 make sure you've got the rights (install the
// Unlimited Crypto Policy files)
aesKeyGenerator.init(128);
SecretKey aesKey = aesKeyGenerator.generateKey();
// --- wrap the new AES secret key ---
byte[] wrappedKey;
try {
wrappedKey = oaep.wrap(aesKey);
} catch (IllegalBlockSizeException e) {
throw new RuntimeException(
"AES key should always fit OAEP with normal sized RSA key", e);
}
// --- setup the AES GCM cipher mode ---
Cipher aesGCM;
try {
aesGCM = Cipher.getInstance("AES/GCM/Nopadding");
// we can get away with a zero nonce since the key is randomly generated
// 128 bits is the recommended (maximum) value for the tag size
// 12 bytes (96 bits) is the default nonce size for GCM mode encryption
GCMParameterSpec staticParameterSpec = new GCMParameterSpec(128, new byte[12]);
aesGCM.init(Cipher.ENCRYPT_MODE, aesKey, staticParameterSpec);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES cipher (mandatory algorithm for runtimes)", e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for GCM (present in the standard Java runtime sinze XX)", e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(
"IvParameterSpec not accepted by this implementation of GCM", e);
}
// --- create a buffer of the right size for our own protocol ---
ByteBuffer ciphertextBuffer = ByteBuffer.allocate(
Short.BYTES
+ oaep.getOutputSize(128 / Byte.SIZE)
+ aesGCM.getOutputSize(plaintext.length));
// - element 1: make sure that we know the size of the wrapped key
ciphertextBuffer.putShort((short) wrappedKey.length);
// - element 2: put in the wrapped key
ciphertextBuffer.put(wrappedKey);
// - element 3: GCM encrypt into buffer
try {
aesGCM.doFinal(plaintextBuffer, ciphertextBuffer);
} catch (ShortBufferException | IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException("Cryptographic exception, AES/GCM encryption should not fail here", e);
}
return ciphertextBuffer.array();
}
물론 암호화는 암호 해독 없이는별로 유용하지 않습니다. 암호 해독에 실패하면 최소한의 정보 만 반환합니다.
/**
* Decrypts the data using a hybrid crypto-system which uses GCM to encrypt
* the data and OAEP to encrypt the AES key. All the default parameter
* choices are used for OAEP and GCM.
*
* @param privateKey
* the RSA private key used to unwrap the AES key
* @param ciphertext
* the ciphertext to be encrypted, not altered
* @return the plaintext
* @throws InvalidKeyException
* if the key is not an RSA private key
* @throws NullPointerException
* if the ciphertext is null
* @throws IllegalArgumentException
* with the message "Invalid ciphertext" if the ciphertext is invalid (minimize information leakage)
*/
public static byte[] decryptData(PrivateKey privateKey, byte[] ciphertext)
throws InvalidKeyException, NullPointerException {
// --- create the RSA OAEP cipher ---
Cipher oaep;
try {
// SHA-1 is the default and not vulnerable in this setting
// use OAEPParameterSpec to configure more than just the hash
oaep = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for RSA cipher (mandatory algorithm for runtimes)",
e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for OAEP padding (present in the standard Java runtime sinze XX)",
e);
}
oaep.init(Cipher.UNWRAP_MODE, privateKey);
// --- wrap the ciphertext in a buffer
// will throw NullPointerException if ciphertext is null
ByteBuffer ciphertextBuffer = ByteBuffer.wrap(ciphertext);
// sanity check #1
if (ciphertextBuffer.remaining() < 2) {
throw new IllegalArgumentException("Invalid ciphertext");
}
// - element 1: the length of the encapsulated key
int wrappedKeySize = ciphertextBuffer.getShort() & 0xFFFF;
// sanity check #2
if (ciphertextBuffer.remaining() < wrappedKeySize + 128 / Byte.SIZE) {
throw new IllegalArgumentException("Invalid ciphertext");
}
// --- unwrap the AES secret key ---
byte[] wrappedKey = new byte[wrappedKeySize];
// - element 2: the encapsulated key
ciphertextBuffer.get(wrappedKey);
SecretKey aesKey;
try {
aesKey = (SecretKey) oaep.unwrap(wrappedKey, "AES",
Cipher.SECRET_KEY);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES cipher (mandatory algorithm for runtimes)",
e);
} catch (InvalidKeyException e) {
throw new RuntimeException(
"Invalid ciphertext");
}
// --- setup the AES GCM cipher mode ---
Cipher aesGCM;
try {
aesGCM = Cipher.getInstance("AES/GCM/Nopadding");
// we can get away with a zero nonce since the key is randomly
// generated
// 128 bits is the recommended (maximum) value for the tag size
// 12 bytes (96 bits) is the default nonce size for GCM mode
// encryption
GCMParameterSpec staticParameterSpec = new GCMParameterSpec(128,
new byte[12]);
aesGCM.init(Cipher.DECRYPT_MODE, aesKey, staticParameterSpec);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Runtime doesn't have support for AES cipher (mandatory algorithm for runtimes)",
e);
} catch (NoSuchPaddingException e) {
throw new RuntimeException(
"Runtime doesn't have support for GCM (present in the standard Java runtime sinze XX)",
e);
} catch (InvalidAlgorithmParameterException e) {
throw new RuntimeException(
"IvParameterSpec not accepted by this implementation of GCM",
e);
}
// --- create a buffer of the right size for our own protocol ---
ByteBuffer plaintextBuffer = ByteBuffer.allocate(aesGCM
.getOutputSize(ciphertextBuffer.remaining()));
// - element 3: GCM ciphertext
try {
aesGCM.doFinal(ciphertextBuffer, plaintextBuffer);
} catch (ShortBufferException | IllegalBlockSizeException
| BadPaddingException e) {
throw new RuntimeException(
"Invalid ciphertext");
}
return plaintextBuffer.array();
}
Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow