it-gundan.com

Java AES / GCM / NoPadding-cipher.getIV ()는 무엇입니까?

Java 8에서 AES/GCM/NoPadding 암호화를 사용하고 있으며 코드에 보안 결함이 있는지 궁금합니다. 내 코드는 work 텍스트를 암호화하고 해독한다는 점에서 몇 가지 세부 사항이 명확하지 않습니다.

내 주요 질문은 이것입니다 :

Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = cipher.getIV(); // ?????

IV가 "주어진 키에 대해 IV를 반복해서는 안됩니다"의 요구 사항을 충족해야합니까? 에서 RFC 4106 ?

또한 관련 질문에 대한 답변/통찰력에 감사드립니다 (아래 참조). 그러나 첫 번째 질문은 나를 가장 많이 괴롭 힙니다. 나는 이것에 대답하는 소스 코드 나 문서를 어디서 찾을 수 있는지 모른다.


전체 코드는 다음과 같습니다. 이 게시물을 작성하는 동안 오류가 발생한 경우 사과드립니다.

class Encryptor {
  Key key;

  Encryptor(byte[] key) {
    if (key.length != 32) throw new IllegalArgumentException();
    this.key = new SecretKeySpec(key, "AES");
  }

  // the output is sent to users
  byte[] encrypt(byte[] src) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(Cipher.ENCRYPT_MODE, key);
    byte[] iv = cipher.getIV(); // See question #1
    assert iv.length == 12; // See question #2
    byte[] cipherText = cipher.doFinal(src);
    assert cipherText.length == src.length + 16; // See question #3
    byte[] message = new byte[12 + src.length + 16]; // See question #4
    System.arraycopy(iv, 0, message, 0, 12);
    System.arraycopy(cipherText, 0, message, 12, cipherText.length);
    return message;
  }

  // the input comes from users
  byte[] decrypt(byte[] message) throws Exception {
    if (message.length < 12 + 16) throw new IllegalArgumentException();
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12);
    cipher.init(Cipher.DECRYPT_MODE, key, params);
    return cipher.doFinal(message, 12, message.length - 12);
  }
}

사용자가 내 비밀 키를 크래킹한다고 가정합시다.


더 자세한 질문/관련 질문 :

  1. Cipher.getIV ()에 의해 반환 된 IV는 이런 방식으로 안전하게 사용할 수 있습니까?

    • Galois/Counter 모드에서 IV, 키 조합을 재사용하는 재앙을 피합니까?
    • 이 코드를 한 번에 실행하는 여러 응용 프로그램이 동일한 src 데이터 (아마도 동일한 밀리 초)의 암호화 된 메시지를 표시하는 경우에도 여전히 안전합니까?
    • 반환 된 IV로 만든 것은 무엇입니까? 원자 카운터에 임의의 노이즈가 있습니까?
    • 카운터를 사용하여 cipher.getIV()을 피하고 IV를 직접 만들어야합니까?
    • Oracle JDK 8 + JCE Unlimited Strength 확장을 사용한다고 가정하고 소스 코드가 cipher.getIV()을 온라인으로 사용할 수 있습니까?
  2. IV가 항상 12 바이트 길이입니까?

  3. 인증 태그의 길이는 항상 16 바이트 (128 비트)입니까?

  4. # 2와 # 3과 패딩이 없기 때문에 암호화 된 메시지의 길이가 항상 12 + src.length + 16 바이트입니까? (따라서 안전하게 올바른 길이를 알 수있는 1 바이트 배열로 안전하게 압축 할 수 있습니까?)

  5. 사용자가 알고있는 일정한 src 데이터가 주어지면 무한한 수의 src 데이터 암호화를 사용자에게 표시하는 것이 안전합니까?

  6. Src 데이터가 매번 다르면 (예 : System.currentTimeMillis() 또는 난수를 포함하여) 무제한의 src 데이터 암호화를 사용자에게 표시해도 안전합니까?

  7. 암호화하기 전에 src 데이터를 임의의 숫자로 채운다면 도움이 될까요? 앞뒤로 8 개의 임의 바이트를 말하거나 한쪽 끝에 만 말합니까? 아니면 전혀 도움이되지/암호화가 악화됩니까?

(이러한 질문은 모두 내 코드의 동일한 블록에 관한 것이며 서로 밀접하게 관련되어 있으며 동일한 기능을 구현할 때 다른 질문과 동일한 질문이있을 수 있으므로 여러 질문으로 나누는 것이 잘못되었다고 느꼈습니다. StackOverflow 형식에 더 적합한 경우 별도로 게시 할 수 있습니다. 알려주세요!)

32
Michael Hixson

Q1 : cipher.getIV ()에 의해 반환 된 IV가 이런 식으로 안전하게 사용할 수 있습니까?

예, 적어도 Oracle에서 제공 한 구현에 해당합니다. 기본 SecureRandom 구현을 사용하여 별도로 생성됩니다. 크기가 12 바이트 (GCM의 기본값)이므로 임의의 96 비트가 있습니다. 카운터가 반복 될 가능성은 아주 작습니다. Oracle JDK의 기반이되는 OpenJDK (GPL)에서 소스를 찾을 수 있습니다.

그러나 다른 공급자가 다르게 작동 할 수 있으므로 12 개의 임의 바이트를 생성하는 것이 좋습니다.


Q2 : IV의 길이는 항상 12 바이트입니까?

GCM 기본값이므로 매우 가능성이 높지만 다른 길이 are GCM에 유효합니다. 그러나 알고리즘은 12 바이트 이외의 다른 크기에 대해 추가 계산을 수행해야합니다. 약점으로 인해 12 바이트/96 비트로 유지하는 것이 좋습니다. API IV 크기 선택으로 제한 할 수 있습니다.


Q3 : 인증 태그의 길이는 항상 16 바이트 (128 비트)입니까?

아니요, 8 비트 단위로 64 비트에서 128 비트 사이의 바이트 크기를 가질 수 있습니다. 더 작 으면 인증 태그의 가장 왼쪽 바이트로 구성됩니다. GCMParameterSpec 호출의 세 번째 매개 변수로 init 를 사용하여 다른 크기의 태그를 지정할 수 있습니다.

GCM의 강도는 태그의 크기에 크게 의존합니다. 128 비트로 유지하는 것이 좋습니다. 많은 암호문을 생성하려면 96 비트가 최소 특히 여야합니다.


Q4 : # 2 및 # 3과 패딩이 없기 때문에 암호화 된 메시지가 항상 12 + src.length + 16 바이트 길이입니까? (따라서 안전하게 올바른 길이를 알 수있는 1 바이트 배열로 안전하게 쓸 수 있습니까?)

위 참조. Oracle 제공자의 경우입니다. GCMParameterSpec를 사용하여 확인하십시오.


Q5 : 사용자가 알고있는 일정한 src 데이터가 주어지면 무제한의 src 데이터 암호화를 사용자에게 표시하는 것이 안전합니까?

거의 약속 안함, 예. 약 2 ^ 48 암호화 후에 걱정하기 시작합니다. 그러나 일반적으로 design for 키 변경이 필요합니다.


Q6 : src 데이터가 매번 다른 경우 (예 : System.currentTimeMillis () 또는 임의의 숫자 포함) 무제한의 src 데이터 암호화를 사용자에게 표시하는 것이 안전합니까?

Q5에 대한 답변보기


Q7 : 암호화하기 전에 src 데이터를 임의의 숫자로 채운다면 도움이 되겠습니까? 앞뒤로 8 개의 임의 바이트를 말하거나 한쪽 끝에 만 말합니까? 아니면 전혀 도움이되지 않거나 암호화를 더 나쁘게 만들 수 있습니까?

아니요, 전혀 도움이되지 않습니다. GCM은 아래에서 CTR 모드를 사용하므로 키 스트림으로 암호화됩니다. not IV 역할을합니다. 사실상 무한한 수의 암호문 (2 ^ 48! 이상)이 필요한 경우 키 파생 함수 또는 KDF에 임의의 숫자와 키를 사용하는 것이 좋습니다. HKDF는 현재 최고의 품종이지만 Bouncy Castle을 사용하거나 직접 구현해야 할 수도 있습니다.

39
Maarten Bodewes