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 davmail.Settings;
23  
24  import javax.crypto.Cipher;
25  import javax.crypto.SecretKey;
26  import javax.crypto.SecretKeyFactory;
27  import javax.crypto.spec.IvParameterSpec;
28  import javax.crypto.spec.PBEKeySpec;
29  import javax.crypto.spec.PBEParameterSpec;
30  import java.io.IOException;
31  import java.nio.charset.StandardCharsets;
32  import java.security.NoSuchAlgorithmException;
33  import java.security.spec.InvalidKeySpecException;
34  
35  /**
36   * Encrypt string using user password.
37   * Simple implementation based on AES
38   */
39  public class StringEncryptor {
40      static final String ALGO = "PBEWithHmacSHA256AndAES_128";
41      static final String DEFAULT_FINGERPRINT = "davmailgateway!&";
42  
43      private final String password;
44  
45      public StringEncryptor(String password) {
46          this.password = password;
47      }
48  
49      public String encryptString(String value) throws IOException {
50          try {
51              byte[] plaintext = value.getBytes(StandardCharsets.UTF_8);
52  
53              // Encrypt
54              Cipher enc = Cipher.getInstance(ALGO);
55              enc.init(Cipher.ENCRYPT_MODE, getSecretKey(), getPBEParameterSpec());
56              byte[] encrypted = enc.doFinal(plaintext);
57              return "{AES}" + IOUtil.encodeBase64AsString(encrypted);
58  
59          } catch (Exception e) {
60              throw new IOException(e);
61          }
62      }
63  
64      public String decryptString(String value) throws IOException {
65          if (value != null && value.startsWith("{AES}")) {
66              try {
67                  byte[] encrypted = IOUtil.decodeBase64(value.substring(5));
68  
69                  Cipher dec = Cipher.getInstance(ALGO);
70                  dec.init(Cipher.DECRYPT_MODE, getSecretKey(), getPBEParameterSpec());
71                  byte[] decrypted = dec.doFinal(encrypted);
72                  return new String(decrypted, StandardCharsets.UTF_8);
73  
74              } catch (Exception e) {
75                  throw new IOException(e);
76              }
77          } else {
78              return value;
79          }
80      }
81  
82      private SecretKey getSecretKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
83          PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
84  
85          SecretKeyFactory kf = SecretKeyFactory.getInstance(ALGO);
86          return kf.generateSecret(keySpec);
87      }
88  
89      private PBEParameterSpec getPBEParameterSpec() {
90          byte[] bytes = Settings.getProperty("davmail.oauth.fingerprint", DEFAULT_FINGERPRINT).getBytes(StandardCharsets.UTF_8);
91          return new PBEParameterSpec(bytes, 10000, new IvParameterSpec(bytes));
92      }
93  }