View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2010  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  
20  package davmail.util;
21  
22  import javax.crypto.Cipher;
23  import javax.crypto.SecretKey;
24  import javax.crypto.SecretKeyFactory;
25  import javax.crypto.spec.IvParameterSpec;
26  import javax.crypto.spec.PBEKeySpec;
27  import javax.crypto.spec.PBEParameterSpec;
28  import java.io.IOException;
29  import java.net.InetAddress;
30  import java.nio.charset.StandardCharsets;
31  import java.security.NoSuchAlgorithmException;
32  import java.security.spec.InvalidKeySpecException;
33  
34  /**
35   * Encrypt string with user password.
36   * Simple implementation based on AES
37   */
38  public class StringEncryptor {
39      static final String ALGO = "PBEWithHmacSHA256AndAES_128";
40      static String fingerprint;
41  
42      static {
43          try {
44              fingerprint = InetAddress.getLocalHost().getCanonicalHostName().substring(0, 16);
45          } catch (Throwable t) {
46              fingerprint = "davmailgateway!&";
47          }
48      }
49  
50      private final String password;
51  
52      public StringEncryptor(String password) {
53          this.password = password;
54      }
55  
56      public String encryptString(String value) throws IOException {
57          try {
58              byte[] plaintext = value.getBytes(StandardCharsets.UTF_8);
59  
60              // Encrypt
61              Cipher enc = Cipher.getInstance(ALGO);
62              enc.init(Cipher.ENCRYPT_MODE, getSecretKey(), getPBEParameterSpec());
63              byte[] encrypted = enc.doFinal(plaintext);
64              return "{AES}" + IOUtil.encodeBase64AsString(encrypted);
65  
66          } catch (Exception e) {
67              throw new IOException(e);
68          }
69      }
70  
71      public String decryptString(String value) throws IOException {
72          if (value != null && value.startsWith("{AES}")) {
73              try {
74                  byte[] encrypted = IOUtil.decodeBase64(value.substring(5));
75  
76                  Cipher dec = Cipher.getInstance(ALGO);
77                  dec.init(Cipher.DECRYPT_MODE, getSecretKey(), getPBEParameterSpec());
78                  byte[] decrypted = dec.doFinal(encrypted);
79                  return new String(decrypted, StandardCharsets.UTF_8);
80  
81              } catch (Exception e) {
82                  throw new IOException(e);
83              }
84          } else {
85              return value;
86          }
87      }
88  
89      private SecretKey getSecretKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
90          PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
91  
92          SecretKeyFactory kf = SecretKeyFactory.getInstance(ALGO);
93          return kf.generateSecret(keySpec);
94      }
95  
96      private PBEParameterSpec getPBEParameterSpec() {
97          byte[] bytes = fingerprint.getBytes(StandardCharsets.UTF_8);
98          return new PBEParameterSpec(bytes, 10000, new IvParameterSpec(bytes));
99      }
100 }