// Copyright 2007 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.enterprise.connector.instantiator;
import com.google.enterprise.connector.test.ConnectorTestUtils;
import junit.framework.TestCase;
import java.io.File;
import java.io.FileWriter;
import java.security.Provider;
import java.security.Security;
import java.util.Random;
import java.security.NoSuchAlgorithmException;
public class CryptoTest extends TestCase {
private static String keyStorePasswdPath = "test_keystore_passwd";
private static final Random random = new Random();
/*
* Create a file with a passwd in it
*/
@Override
protected void setUp() throws Exception {
FileWriter fw = new FileWriter(keyStorePasswdPath);
fw.write("dummy password");
fw.close();
}
@Override
protected void tearDown() throws Exception {
File keyStoreFile = new File(
EncryptedPropertyPlaceholderConfigurer.getKeyStorePath());
ConnectorTestUtils.deleteAllFiles(keyStoreFile);
File keyPasswdFile = new File(keyStorePasswdPath);
ConnectorTestUtils.deleteAllFiles(keyPasswdFile);
// delete keystore that might exist
ConnectorTestUtils.deleteAllFiles(
new File(EncryptedPropertyPlaceholderConfigurer.getKeyStorePath()));
}
private void encryptAndDecrypt() {
encryptAndDecrypt("", "this is clear");
}
private void encryptAndDecrypt(String message, String plainText) {
String cipherText =
EncryptedPropertyPlaceholderConfigurer.encryptString(plainText);
assertEncryption(message, plainText, cipherText);
}
private void encryptAndDecrypt(String message, char[] plainText) {
String cipherText =
EncryptedPropertyPlaceholderConfigurer.encryptChars(plainText);
assertEncryption(message, new String(plainText), cipherText);
}
private void assertEncryption(String message, String plainText,
String cipherText) {
assertNotNull(cipherText);
assertFalse(plainText, cipherText.equals(plainText));
assertTrue(cipherText.length() >= plainText.length());
String decryptText =
EncryptedPropertyPlaceholderConfigurer.decryptString(cipherText);
assertEquals(message, plainText, decryptText);
}
/*
* Tests encryption and decryption when no keystore password file
* is specified.
*/
public final void testEncryptDecryptWithoutKeyStorePasswd() {
encryptAndDecrypt();
}
/*
* Tests encryption and decryption when given a keystore passwd in a file.
*/
public final void testEncryptDecryptWithKeyStorePasswd() {
EncryptedPropertyPlaceholderConfigurer.setKeyStorePasswdPath(
keyStorePasswdPath);
encryptAndDecrypt();
}
/*
* Tests encryption and decryption when given a keystore passwd file that
* does not exist.
*/
public final void testEncryptDecryptWithBadKeyStorePasswd() {
EncryptedPropertyPlaceholderConfigurer.setKeyStorePasswdPath("bogusfile");
encryptAndDecrypt();
}
private char[] randomChars(int length) {
byte[] bytes = new byte[length];
random.nextBytes(bytes);
char[] chars = new char[length];
for (int i = 0; i < i; i++) {
chars[i] = (char) (bytes[i] & 0xFF);
}
return chars;
}
public void testStrings() {
for (int i = 1; i < 100; i++) {
encryptAndDecrypt("Length " + i, new String(randomChars(i)));
}
}
public void testChars() {
for (int i = 1; i < 100; i++) {
encryptAndDecrypt("Length " + i, randomChars(i));
}
}
public void testDecryptEmptyString() {
assertEquals("", decryptWithoutCipher(""));
}
public void testDecryptException() {
try {
decryptWithoutCipher("hello, world");
fail("expected a NoSuchAlgorithmException wrapped in a RuntimeException");
} catch (RuntimeException expected) {
// Look up the cause chain for a NoSuchAlgorithmException. It is
// nested differently in Java 8 and earlier versions.
Throwable t = expected;
while ((t = t.getCause()) != null) {
if (t instanceof NoSuchAlgorithmException) {
return;
}
}
throw expected;
}
}
/**
* Tests decrypting the given string without access to ciphers.
* Ciphers and Providers are hard to mock, because they must be
* loaded from a signed JAR file. So we just remove all the
* providers to make sure that no Cipher is used when decrypting the
* empty string.
*/
private String decryptWithoutCipher(String cipherText) {
Provider[] providers = Security.getProviders();
for (Provider p : providers) {
Security.removeProvider(p.getName());
}
try {
return EncryptedPropertyPlaceholderConfigurer.decryptString(cipherText);
} finally {
for (Provider p : providers) {
Security.addProvider(p);
}
}
}
}