001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> 
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.crypto;
019
020import java.util.ArrayList;
021import java.util.List;
022import java.util.Map;
023import java.util.TreeMap;
024
025import org.syncany.crypto.specs.AesGcm128CipherSpec;
026import org.syncany.crypto.specs.AesGcm256CipherSpec;
027import org.syncany.crypto.specs.TwofishGcm128CipherSpec;
028import org.syncany.crypto.specs.TwofishGcm256CipherSpec;
029
030/**
031 * Defines and identifies the application supported {@link CipherSpec}s.
032 * 
033 * <p>These cipher specs are used by the {@link MultiCipherOutputStream} to encrypt
034 * data, and by the {@link MultiCipherInputStream} to decrypt data. The cipher spec
035 * identifiers are used in the crypto format header to identify the crypto algorithms
036 * used for encryption.
037 * 
038 * <p>The class defines a well defined (and developer-approved) set of allowed
039 * cipher algorithms, modes and key sizes. The number of allowed ciphers is greatly
040 * restricted to follow the application-specific security standards. Most prominently,
041 * this includes:
042 * 
043 * <ul>
044 *   <li>The block cipher mode must be authenticated (GCM, EAX, etc.). Unauthenticated
045 *       modes are not supported and will be rejected by the {@link CipherSpec} sanity checks.
046 *   <li>The block cipher mode must require an initialization vector (IV). Modes that do 
047 *       not require an IV (e.g. ECB) will be rejected by the {@link CipherSpec} sanity checks.
048 * </ul>
049 * 
050 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
051 */
052public class CipherSpecs {
053        private static final Map<Integer, CipherSpec> cipherSpecs = new TreeMap<Integer, CipherSpec>();
054
055        /*
056         * WARNING: The cipher spec identifiers are written to the MultiCipherOutputStream and read by the MultiCipherInputStream. The identifiers MUST
057         * NOT be changed, because this will make decryption of already encrypted data impossible!
058         */
059        public static final int AES_128_GCM = 0x01;
060        public static final int TWOFISH_128_GCM = 0x02;
061        public static final int AES_256_GCM = 0x03;
062        public static final int TWOFISH_256_GCM = 0x04;
063
064        public static final int[] DEFAULT_CIPHER_SPECS = new int[] { CipherSpecs.AES_128_GCM };
065
066        static {
067                CipherSpec[] tmpCipherSpecs = new CipherSpec[] {
068                                // Standard
069                                new AesGcm128CipherSpec(),
070                                new TwofishGcm128CipherSpec(),
071
072                                // Unlimited crypto
073                                new AesGcm256CipherSpec(),
074                                new TwofishGcm256CipherSpec() 
075                        };
076
077                for (CipherSpec cipherSpec : tmpCipherSpecs) {
078                        registerCipherSpec(cipherSpec.getId(), cipherSpec);
079                }
080        }
081
082        /**
083         * Returns a list of available/registered {@link CipherSpec}s. Refer to the 
084         * {@link CipherSpecs class description} for a more detailed explanation.
085         */
086        public static Map<Integer, CipherSpec> getAvailableCipherSpecs() {
087                return cipherSpecs;
088        }
089        
090        /**
091         * Returns the default {@link CipherSpec}s used by the application.
092         */
093        public static List<CipherSpec> getDefaultCipherSpecs() {
094                List<CipherSpec> cipherSpecs = new ArrayList<CipherSpec>();
095                
096                for (int cipherSpecId : DEFAULT_CIPHER_SPECS) { 
097                        cipherSpecs.add(getCipherSpec(cipherSpecId));
098                }       
099                
100                return cipherSpecs;
101        }
102
103        /**
104         * Retrieves an available/registered {@link CipherSpec} using the cipher spec identifier
105         * defined in this class.
106         * 
107         * @param id Identifier of the cipher spec
108         * @return A cipher spec, or <code>null</code> if no cipher spec with this identifier is registered
109         */
110        public static CipherSpec getCipherSpec(int id) {
111                return cipherSpecs.get(id);
112        }
113
114        /**
115         * Register a new cipher spec.
116         * 
117         * <p>Note: Registering a cipher spec locally does not make it available on all clients. Unless
118         * a cipher spec is registered before a client tries to decrypt data using the {@link MultiCipherInputStream},
119         * the decryption process will fail. 
120         * 
121         * @param id Identifier of the cipher spec
122         */
123        public static void registerCipherSpec(int id, CipherSpec cipherSpec) {
124                cipherSpecs.put(id, cipherSpec);
125        }
126}