/* * Syncany, www.syncany.org * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.syncany.crypto; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import org.syncany.crypto.specs.AesGcm128CipherSpec; import org.syncany.crypto.specs.AesGcm256CipherSpec; import org.syncany.crypto.specs.TwofishGcm128CipherSpec; import org.syncany.crypto.specs.TwofishGcm256CipherSpec; /** * Defines and identifies the application supported {@link CipherSpec}s. * * <p>These cipher specs are used by the {@link MultiCipherOutputStream} to encrypt * data, and by the {@link MultiCipherInputStream} to decrypt data. The cipher spec * identifiers are used in the crypto format header to identify the crypto algorithms * used for encryption. * * <p>The class defines a well defined (and developer-approved) set of allowed * cipher algorithms, modes and key sizes. The number of allowed ciphers is greatly * restricted to follow the application-specific security standards. Most prominently, * this includes: * * <ul> * <li>The block cipher mode must be authenticated (GCM, EAX, etc.). Unauthenticated * modes are not supported and will be rejected by the {@link CipherSpec} sanity checks. * <li>The block cipher mode must require an initialization vector (IV). Modes that do * not require an IV (e.g. ECB) will be rejected by the {@link CipherSpec} sanity checks. * </ul> * * @author Philipp C. Heckel <philipp.heckel@gmail.com> */ public class CipherSpecs { private static final Map<Integer, CipherSpec> cipherSpecs = new TreeMap<Integer, CipherSpec>(); /* * WARNING: The cipher spec identifiers are written to the MultiCipherOutputStream and read by the MultiCipherInputStream. The identifiers MUST * NOT be changed, because this will make decryption of already encrypted data impossible! */ public static final int AES_128_GCM = 0x01; public static final int TWOFISH_128_GCM = 0x02; public static final int AES_256_GCM = 0x03; public static final int TWOFISH_256_GCM = 0x04; public static final int[] DEFAULT_CIPHER_SPECS = new int[] { CipherSpecs.AES_128_GCM }; static { CipherSpec[] tmpCipherSpecs = new CipherSpec[] { // Standard new AesGcm128CipherSpec(), new TwofishGcm128CipherSpec(), // Unlimited crypto new AesGcm256CipherSpec(), new TwofishGcm256CipherSpec() }; for (CipherSpec cipherSpec : tmpCipherSpecs) { registerCipherSpec(cipherSpec.getId(), cipherSpec); } } /** * Returns a list of available/registered {@link CipherSpec}s. Refer to the * {@link CipherSpecs class description} for a more detailed explanation. */ public static Map<Integer, CipherSpec> getAvailableCipherSpecs() { return cipherSpecs; } /** * Returns the default {@link CipherSpec}s used by the application. */ public static List<CipherSpec> getDefaultCipherSpecs() { List<CipherSpec> cipherSpecs = new ArrayList<CipherSpec>(); for (int cipherSpecId : DEFAULT_CIPHER_SPECS) { cipherSpecs.add(getCipherSpec(cipherSpecId)); } return cipherSpecs; } /** * Retrieves an available/registered {@link CipherSpec} using the cipher spec identifier * defined in this class. * * @param id Identifier of the cipher spec * @return A cipher spec, or <tt>null</tt> if no cipher spec with this identifier is registered */ public static CipherSpec getCipherSpec(int id) { return cipherSpecs.get(id); } /** * Register a new cipher spec. * * <p>Note: Registering a cipher spec locally does not make it available on all clients. Unless * a cipher spec is registered before a client tries to decrypt data using the {@link MultiCipherInputStream}, * the decryption process will fail. * * @param id Identifier of the cipher spec */ public static void registerCipherSpec(int id, CipherSpec cipherSpec) { cipherSpecs.put(id, cipherSpec); } }