MATSIM
CipherUtils.java
Go to the documentation of this file.
1 package org.matsim.core.utils.io;
2 
3 import com.google.common.io.CharStreams;
4 
5 import javax.crypto.Cipher;
6 import javax.crypto.CipherInputStream;
7 import javax.crypto.SecretKeyFactory;
8 import javax.crypto.spec.IvParameterSpec;
9 import javax.crypto.spec.PBEKeySpec;
10 import javax.crypto.spec.SecretKeySpec;
11 import java.io.FileInputStream;
12 import java.io.IOException;
13 import java.io.InputStream;
14 import java.io.InputStreamReader;
15 import java.nio.charset.StandardCharsets;
16 import java.security.GeneralSecurityException;
17 import java.security.Key;
18 import java.security.NoSuchAlgorithmException;
19 import java.security.spec.InvalidKeySpecException;
20 import java.util.Arrays;
21 
38 public class CipherUtils {
39 
40  public static final String ENVIRONMENT_VARIABLE = "MATSIM_DECRYPTION_PASSWORD";
41 
42  private CipherUtils() {
43  }
44 
45  private static Key getKeyForFile(byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
46 
47  SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
48 
49  String pw = System.getProperty(ENVIRONMENT_VARIABLE, System.getenv(ENVIRONMENT_VARIABLE));
50 
51  if (pw == null)
52  throw new IllegalStateException("No password specified for encrypted file. Please set " + ENVIRONMENT_VARIABLE + " environment variable.");
53 
54  // generates 256bit key and 128bit iv
55  PBEKeySpec keySpec = new PBEKeySpec(pw.toCharArray(), salt, 10000, 256 + 128);
56 
57  return factory.generateSecret(keySpec);
58  }
59 
60 
68  public static InputStream getDecryptedInput(InputStream is) throws IOException, GeneralSecurityException {
69 
70  byte[] header = new byte[16];
71 
72  if (is.read(header) != 16)
73  throw new IllegalStateException("Read too few bytes. Encrypted file is most likely corrupted.");
74 
75  String h = new String(header, 0, 8, StandardCharsets.US_ASCII);
76 
77  if (!h.equals("Salted__"))
78  throw new IllegalStateException("File header must start with 'Salted__'.");
79 
80  byte[] salt = Arrays.copyOfRange(header, 8, 16);
81 
82  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
83 
84  Key tmp = getKeyForFile(salt);
85 
86  SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), 0, 32, "AES");
87  IvParameterSpec ivspec = new IvParameterSpec(tmp.getEncoded(), 32, 16);
88 
89  cipher.init(Cipher.DECRYPT_MODE, secretKey, ivspec);
90 
91  return new CipherInputStream(is, cipher);
92  }
93 
94 
95  public static void main(String[] args) throws Exception {
96 
97  System.setProperty(CipherUtils.ENVIRONMENT_VARIABLE, "abc123");
98 
99  InputStream is = getDecryptedInput(new FileInputStream("some.secret.enc"));
100 
101  System.out.println(CharStreams.toString(new InputStreamReader(is)));
102 
103  }
104 
105 }
static final String ENVIRONMENT_VARIABLE
static InputStream getDecryptedInput(InputStream is)
static void main(String[] args)
static Key getKeyForFile(byte[] salt)