org.silverpeas.core.security.encryption.ContentEncryptionServiceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.silverpeas.core.security.encryption.ContentEncryptionServiceTest.java

Source

/*
 * Copyright (C) 2000 - 2018 Silverpeas
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * As a special exception to the terms and conditions of version 3.0 of
 * the GPL, you may redistribute this Program in connection with Free/Libre
 * Open Source Software ("FLOSS") applications as described in Silverpeas's
 * FLOSS exception.  You should have received a copy of the text describing
 * the FLOSS exception, and it is also available here:
 * "https://www.silverpeas.org/legal/floss_exception.html"
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.silverpeas.core.security.encryption;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.silverpeas.core.admin.user.model.UserDetail;
import org.silverpeas.core.security.encryption.cipher.Cipher;
import org.silverpeas.core.security.encryption.cipher.CipherFactory;
import org.silverpeas.core.security.encryption.cipher.CipherKey;
import org.silverpeas.core.security.encryption.cipher.CryptographicAlgorithmName;
import org.silverpeas.core.test.extention.EnableSilverTestEnv;
import org.silverpeas.core.util.EncodingUtil;
import org.silverpeas.core.util.StringUtil;
import org.silverpeas.core.util.file.FileRepositoryManager;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.Security;
import java.text.ParseException;
import java.util.Random;

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

/**
 * The base class of all tests on the services provided by the DefaultContentEncryptionService instances.
 * It allocates all the required resources for the tests and frees them once the tests are done.
 * It creates the security directory to receive the key file, but the key file and it constructs
 * a DefaultContentEncryptionService instance ready to be tested.
 */
@EnableSilverTestEnv
public abstract class ContentEncryptionServiceTest {

    String ACTUAL_KEY_FILE_PATH;
    String DEPRECATED_KEY_FILE_PATH;
    private CipherKey CIPHER_KEY;

    private DefaultContentEncryptionService service;

    @BeforeEach
    public void setUp() throws Exception {
        createSecurityDirectoryAndSetupJCEProviders();
    }

    @AfterEach
    public void tearDown() throws Exception {
        deleteSecurityDirectory();
    }

    private void createSecurityDirectoryAndSetupJCEProviders() throws IOException {
        ACTUAL_KEY_FILE_PATH = FileRepositoryManager.getSecurityDirPath() + ".aid_key";
        DEPRECATED_KEY_FILE_PATH = FileRepositoryManager.getSecurityDirPath() + ".did_key";
        try {
            CIPHER_KEY = CipherKey.aKeyFromHexText("06277d1ce530c94bd9a13a72a58342be");
        } catch (ParseException e) {
            throw new RuntimeException("Cannot create the cryptographic key!", e);
        }

        String securityPath = FileRepositoryManager.getSecurityDirPath();
        File securityDir = new File(securityPath);
        if (!securityDir.exists()) {
            FileUtils.forceMkdir(securityDir);
        }
        securityDir.setWritable(true);
        securityDir.setExecutable(true);
        securityDir.setReadable(true);
        if (System.getProperty("os.name").toLowerCase().contains("windows")) {
            Runtime.getRuntime().exec("attrib +H " + securityPath);
        }

        Security.addProvider(new BouncyCastleProvider());
    }

    private void deleteSecurityDirectory() throws IOException {
        String securityPath = FileRepositoryManager.getSecurityDirPath();
        File securityDir = new File(securityPath);
        if (securityDir.exists()) {
            File keyFile = new File(ACTUAL_KEY_FILE_PATH);
            if (keyFile.exists()) {
                keyFile.setWritable(true);
                FileUtils.forceDelete(keyFile);
            }
            keyFile = new File(DEPRECATED_KEY_FILE_PATH);
            if (keyFile.exists()) {
                keyFile.setWritable(true);
                FileUtils.forceDelete(keyFile);
            }
            FileUtils.forceDelete(securityDir);
        }
    }

    @BeforeEach
    public void setUpContentEncryptionService() throws Exception {
        service = new DefaultContentEncryptionService();
    }

    @AfterEach
    public void deleteKeyFile() throws Exception {
        File keyFile = new File(ACTUAL_KEY_FILE_PATH);
        if (keyFile.exists()) {
            keyFile.setWritable(true);
            FileUtils.forceDelete(keyFile);
        }
        keyFile = new File(DEPRECATED_KEY_FILE_PATH);
        if (keyFile.exists()) {
            keyFile.setWritable(true);
            FileUtils.forceDelete(keyFile);
        }
    }

    public DefaultContentEncryptionService getContentEncryptionService() {
        return service;
    }

    /**
     * Generates a key for an AES enciphering.
     * @return the key in hexadecimal.
     * @throws Exception if the key cannot be generated.
     */
    public static String generateAESKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256);
        SecretKey skey = keyGenerator.generateKey();
        return EncodingUtil.asHex(skey.getEncoded());
    }

    /**
     * Creates the key file with the specified actual key in hexadecimal.
     * @param key the key used in a content encryption and to store in the key file.
     * @throws Exception if the key file creation failed.
     */
    public void createKeyFileWithTheActualKey(String key) throws Exception {
        File keyFile = new File(ACTUAL_KEY_FILE_PATH);
        if (keyFile.exists()) {
            keyFile.setWritable(true);
        } else {
            System.out.println("WARNIIIINNNNNG: the key file " + ACTUAL_KEY_FILE_PATH + " DOESN'T EXIST!");
        }
        String encryptedKey = encryptKey(key);
        String encryptedContent = StringUtil.asBase64(CIPHER_KEY.getRawKey()) + " " + encryptedKey;
        Files.copy(new ByteArrayInputStream(encryptedContent.getBytes()), keyFile.toPath(), REPLACE_EXISTING);
        keyFile.setReadOnly();
    }

    /**
     * Creates the key file with the specified deprecated key in hexadecimal.
     * @param key the key used in a content encryption and to store in the old key file.
     * @throws Exception if the key file creation failed.
     */
    public void createKeyFileWithTheDeprecatedKey(String key) throws Exception {
        File keyFile = new File(DEPRECATED_KEY_FILE_PATH);
        if (keyFile.exists()) {
            keyFile.setWritable(true);
        }
        String encryptedKey = encryptKey(key);
        String encryptedContent = StringUtil.asBase64(CIPHER_KEY.getRawKey()) + " " + encryptedKey;
        Files.copy(new ByteArrayInputStream(encryptedContent.getBytes()), keyFile.toPath(), REPLACE_EXISTING);
        keyFile.setReadOnly();
    }

    /**
     * Generates the specified count of text contents for testing purpose.
     * @param count the number of text contents to generate.
     * @return an array with the generated text contents.
     */
    public static TextContent[] generateTextContents(int count) {
        TextContent[] contents = new TextContent[count];
        UserDetail creator = new UserDetail();
        creator.setFirstName("Bart");
        creator.setLastName("Simpson");
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            TextContent aContent = new TextContent(String.valueOf(i), "", creator);
            aContent.setTitle(RandomStringUtils.randomAscii(random.nextInt(32)));
            aContent.setDescription(RandomStringUtils.randomAscii(random.nextInt(128)));
            aContent.setText(RandomStringUtils.randomAscii(random.nextInt(1024)));
            contents[i] = aContent;
        }
        return contents;
    }

    /**
     * Encrypts the specified text contents by using the specified cipher key in hexadecimal.
     * @param contents the contents to encrypt.
     * @param key the cipher key to use in hexadecimal.
     * @return an array with the encrypted text contents.
     * @throws Exception if an error occurs while encrypting the contents.
     */
    public static TextContent[] encryptTextContents(TextContent[] contents, String key) throws Exception {
        CipherFactory cipherFactory = CipherFactory.getFactory();
        Cipher aes = cipherFactory.getCipher(CryptographicAlgorithmName.AES);
        CipherKey cipherKey = CipherKey.aKeyFromHexText(key);
        TextContent[] encryptedContents = new TextContent[contents.length];
        for (int i = 0; i < contents.length; i++) {
            TextContent content = new TextContent(contents[i].getId(), contents[i].getComponentInstanceId(),
                    contents[i].getCreator());
            content.setTitle(StringUtil.asBase64(aes.encrypt(contents[i].getTitle(), cipherKey)));
            content.setDescription(StringUtil.asBase64(aes.encrypt(contents[i].getDescription(), cipherKey)));
            content.setText(StringUtil.asBase64(aes.encrypt(contents[i].getText(), cipherKey)));
            encryptedContents[i] = content;
        }
        return encryptedContents;
    }

    private String encryptKey(String key) throws Exception {
        CipherFactory cipherFactory = CipherFactory.getFactory();
        Cipher cast5 = cipherFactory.getCipher(CryptographicAlgorithmName.CAST5);
        byte[] encryptedKey = cast5.encrypt(key, CIPHER_KEY);
        return StringUtil.asBase64(encryptedKey);
    }
}