// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package com.google.crypto.tink.daead;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;

import com.google.crypto.tink.DeterministicAead;
import com.google.crypto.tink.TestUtil;
import com.google.crypto.tink.proto.AesSivKey;
import com.google.crypto.tink.proto.AesSivKeyFormat;
import com.google.crypto.tink.proto.KeyData.KeyMaterialType;
import com.google.crypto.tink.subtle.Random;
import com.google.protobuf.ByteString;
import java.security.GeneralSecurityException;
import java.util.TreeSet;
import javax.crypto.Cipher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Test for AesSivKeyManager. */
@RunWith(JUnit4.class)
public class AesSivKeyManagerTest {
  @Test
  public void basics() throws Exception {
    assertThat(new AesSivKeyManager().getKeyType())
        .isEqualTo("type.googleapis.com/google.crypto.tink.AesSivKey");
    assertThat(new AesSivKeyManager().getVersion()).isEqualTo(0);
    assertThat(new AesSivKeyManager().keyMaterialType()).isEqualTo(KeyMaterialType.SYMMETRIC);
  }

  @Test
  public void validateKeyFormat_empty() throws Exception {
    try {
      new AesSivKeyManager().keyFactory().validateKeyFormat(AesSivKeyFormat.getDefaultInstance());
      fail();
    } catch (GeneralSecurityException e) {
      // expected
    }
  }

  @Test
  public void validateKeyFormat_checkAllLengths() throws Exception {
    AesSivKeyManager manager = new AesSivKeyManager();
    for (int i = 0; i < 100; i++) {
      if (i == 64) {
        manager.keyFactory().validateKeyFormat(createAesSivKeyFormat(i));
      } else {
        try {
          manager.keyFactory().validateKeyFormat(createAesSivKeyFormat(i));
          fail();
        } catch (GeneralSecurityException e) {
          // expected
        }
      }
    }
  }

  @Test
  public void validateKey_empty() throws Exception {
    try {
      new AesSivKeyManager().validateKey(AesSivKey.getDefaultInstance());
      fail();
    } catch (GeneralSecurityException e) {
      // expected
    }
  }

  @Test
  public void validateKey_checkAllLengths() throws Exception {
    AesSivKeyManager manager = new AesSivKeyManager();
    for (int i = 0; i < 100; i++) {
      if (i == 64) {
        manager.validateKey(createAesSivKey(i));
      } else {
        try {
          manager.validateKey(createAesSivKey(i));
          fail();
        } catch (GeneralSecurityException e) {
          // expected
        }
      }
    }
  }

  @Test
  public void validateKey_version() throws Exception {
    AesSivKeyManager manager = new AesSivKeyManager();

    for (int i = 0; i < 100; i++) {
      if (i == 64) {
        manager.validateKey(createAesSivKey(i));
      } else {
        try {
          manager.validateKey(createAesSivKey(i));
          fail();
        } catch (GeneralSecurityException e) {
          // expected
        }
      }
    }
  }

  @Test
  public void createKey_valid() throws Exception {
    AesSivKeyFormat format = createAesSivKeyFormat(64);
    AesSivKey key = new AesSivKeyManager().keyFactory().createKey(format);
    new AesSivKeyManager().validateKey(key);
  }

  @Test
  public void createKey_values() throws Exception {
    AesSivKeyFormat format = createAesSivKeyFormat(64);
    AesSivKey key = new AesSivKeyManager().keyFactory().createKey(format);
    assertThat(key.getVersion()).isEqualTo(0);
    assertThat(key.getKeyValue()).hasSize(format.getKeySize());
  }

  @Test
  public void createKey_multipleCallsCreateDifferentKeys() throws Exception {
    AesSivKeyFormat format = createAesSivKeyFormat(64);
    TreeSet<String> keys = new TreeSet<>();
    AesSivKeyManager.KeyFactory<AesSivKeyFormat, AesSivKey> factory =
        new AesSivKeyManager().keyFactory();
    final int numKeys = 1000;
    for (int i = 0; i < numKeys; ++i) {
      keys.add(TestUtil.hexEncode(factory.createKey(format).toByteArray()));
    }
    assertThat(keys).hasSize(numKeys);
  }

  @Test
  public void testCiphertextSize() throws Exception {
    if (Cipher.getMaxAllowedKeyLength("AES") < 256) {
      System.out.println(
          "Unlimited Strength Jurisdiction Policy Files are required"
              + " but not installed. Skipping testCiphertextSize");
      return;
    }

    DeterministicAead daead =
        new AesSivKeyManager().getPrimitive(createAesSivKey(64), DeterministicAead.class);
    byte[] plaintext = "plaintext".getBytes("UTF-8");
    byte[] associatedData = "associatedData".getBytes("UTF-8");
    assertThat(daead.encryptDeterministically(plaintext, associatedData))
        .hasLength(plaintext.length + /* IV_SIZE= */ 16);
  }

  private AesSivKeyFormat createAesSivKeyFormat(int keySize) {
    return AesSivKeyFormat.newBuilder().setKeySize(keySize).build();
  }

  private AesSivKey createAesSivKey(int keySize) {
    return AesSivKey.newBuilder()
        .setKeyValue(ByteString.copyFrom(Random.randBytes(keySize)))
        .build();
  }
}

@@ -3285,68 +3285,18 @@
 ();%0A
-%0A
     
-for (int i = 0; i %3C 100; i++) %7B%0A      if (i == 64)
+try
  %7B%0A
-  
     
@@ -3309,38 +3309,32 @@
 ger.validateKey(
-create
 AesSivKey(i));%0A 
@@ -3330,98 +3330,65 @@
 vKey
-(i));%0A      %7D else %7B%0A        try %7B%0A          manager.validateKey(createAesSivKey(i));%0A    
+.newBuilder(createAesSivKey(64)).setVersion(1).build());%0A
     
@@ -3389,36 +3389,32 @@
 ;%0A      fail();%0A
-    
     %7D catch (Gen
@@ -3438,36 +3438,32 @@
 tion e) %7B%0A      
-    
 // expected%0A    
@@ -3458,34 +3458,16 @@
 xpected%0A
-        %7D%0A      %7D%0A
     %7D%0A  

Fix a test in the AesSivKeyManagerTest to actually check the right thing (namely, if the wrong version makes validateKey fail).