View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.crypto;
21  
22  import org.waarp.common.exception.CryptoException;
23  import org.waarp.common.file.FileUtils;
24  import org.waarp.common.utility.WaarpStringUtils;
25  
26  import java.io.File;
27  import java.io.FileInputStream;
28  import java.io.FileNotFoundException;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.util.Enumeration;
32  import java.util.LinkedList;
33  import java.util.List;
34  
35  /**
36   * Can implements AES, ARCFOUR, Blowfish, DES, DESede, RC2, RC4<br>
37   * <br>
38   * The time ratio are: RC4,ARCFOUR=1; AES,RC2=1,5; DES=2; Blowfish,DESede=4<br>
39   * <b>AES is the best compromise in term of security and efficiency.</b>
40   */
41  public class DynamicKeyManager extends KeyManager {
42    /**
43     * Manager of Dynamic Key
44     */
45    private static final DynamicKeyManager manager = new DynamicKeyManager();
46    /**
47     * Extra information file extension
48     */
49    private static final String INFEXTENSION = ".inf";
50  
51    /**
52     * @return the current KeyManager
53     */
54    public static KeyManager getInstance() {
55      return manager;
56    }
57  
58    @Override
59    public final KeyObject createKeyObject() {
60      throw new InstantiationError(
61          "DynamicKeyManager does not implement this function");
62    }
63  
64    @Override
65    public final List<String> initFromList(final List<String> keys) {
66      final LinkedList<String> wrong = new LinkedList<String>();
67      for (final String filename : keys) {
68        final File file = new File(filename);
69        if (file.canRead()) {
70          final String basename = file.getName();
71          final int lastpos = basename.lastIndexOf('.');
72          if (lastpos <= 0) {
73            wrong.add(filename);
74            continue;
75          }
76          final String firstname = basename.substring(0, lastpos);
77          final String extension = basename.substring(lastpos + 1);
78          int len = (int) file.length();
79          final byte[] key = new byte[len];
80          FileInputStream inputStream;
81          try {
82            inputStream = new FileInputStream(file);
83          } catch (final FileNotFoundException e) {
84            // should not be
85            wrong.add(filename);
86            continue;
87          }
88          int read = 1;
89          int offset = 0;
90          while (read > 0) {
91            try {
92              read = inputStream.read(key, offset, len);
93            } catch (final IOException e) {
94              wrong.add(filename);
95              read = -2;
96              break;
97            }
98            offset += read;
99            if (offset < len) {
100             len -= read;
101           } else {
102             break;
103           }
104         }
105         FileUtils.close(inputStream);
106         if (read < -1) {
107           // wrong
108           continue;
109         }
110         final String infFilename = filename + INFEXTENSION;
111         final File infFile = new File(infFilename);
112         inputStream = null;
113         try {
114           inputStream = new FileInputStream(infFile);
115         } catch (final FileNotFoundException e) {
116           // should not be
117           wrong.add(filename);
118           continue;
119         }
120         KeyObject keyObject;
121         try {
122           final int keySize = inputStream.read();
123           final String algo = readString(inputStream);
124           if (algo == null) {
125             wrong.add(filename);
126             continue;
127           }
128           final String instance = readString(inputStream);
129           if (instance == null) {
130             wrong.add(filename);
131             continue;
132           }
133           keyObject = new DynamicKeyObject(keySize, algo, instance, extension);
134         } catch (final IOException e1) {
135           wrong.add(filename);
136           continue;
137         } finally {
138           FileUtils.close(inputStream);
139         }
140         keyObject.setSecretKey(key);
141         setKey(firstname, keyObject);
142       } else {
143         wrong.add(filename);
144       }
145     }
146     isInitialized.set(true);
147     return wrong;
148   }
149 
150   /**
151    * Specific functions to ease the process of reading the "inf" file
152    *
153    * @param inputStream
154    *
155    * @return the String that should be read
156    */
157   private String readString(final FileInputStream inputStream) {
158     final int len;
159     try {
160       len = inputStream.read();
161     } catch (final IOException e1) {
162       return null;
163     }
164     final byte[] readbyte = new byte[len];
165     for (int i = 0; i < len; i++) {
166       try {
167         readbyte[i] = (byte) inputStream.read();
168       } catch (final IOException e) {
169         return null;
170       }
171     }
172     return new String(readbyte, WaarpStringUtils.UTF8);
173   }
174 
175   @Override
176   public final void saveToFiles() throws CryptoException, IOException {
177     final Enumeration<String> names = keysConcurrentHashMap.keys();
178     while (names.hasMoreElements()) {
179       final String name = names.nextElement();
180       final KeyObject key = keysConcurrentHashMap.get(name);
181       key.saveSecretKey(new File(name + '.' + key.getFileExtension()));
182       final FileOutputStream outputStream = new FileOutputStream(
183           new File(name + '.' + key.getFileExtension() + INFEXTENSION));
184       try {
185         outputStream.write(key.getKeySize());
186         final String algo = key.getAlgorithm();
187         final String instance = key.getInstance();
188         outputStream.write(algo.length());
189         outputStream.write(algo.getBytes(WaarpStringUtils.UTF8));
190         outputStream.write(instance.length());
191         outputStream.write(instance.getBytes(WaarpStringUtils.UTF8));
192       } finally {
193         FileUtils.close(outputStream);
194       }
195     }
196   }
197 
198 }