Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
LicenseDecryptorUtil.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2023 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package com.basistech.df.cybertriage.autopsy.ctapi.util;
20 
25 import com.fasterxml.jackson.core.JsonProcessingException;
26 import com.fasterxml.jackson.databind.ObjectMapper;
27 import java.io.IOException;
28 import java.nio.charset.StandardCharsets;
29 import java.security.GeneralSecurityException;
30 import java.security.InvalidKeyException;
31 import java.security.KeyFactory;
32 import java.security.NoSuchAlgorithmException;
33 import java.security.PublicKey;
34 import java.security.spec.InvalidKeySpecException;
35 import java.security.spec.KeySpec;
36 import java.security.spec.X509EncodedKeySpec;
37 import java.text.MessageFormat;
38 import java.util.Base64;
39 import javax.crypto.BadPaddingException;
40 import javax.crypto.Cipher;
41 import javax.crypto.IllegalBlockSizeException;
42 import javax.crypto.NoSuchPaddingException;
43 import javax.crypto.SecretKey;
44 import javax.crypto.spec.IvParameterSpec;
45 import javax.crypto.spec.SecretKeySpec;
46 import org.apache.commons.lang3.ObjectUtils;
47 
51 public class LicenseDecryptorUtil {
52 
53  private static final LicenseDecryptorUtil instance = new LicenseDecryptorUtil();
54 
56  return instance;
57  }
58 
60 
62  }
63 
64  public LicenseInfo createLicenseInfo(LicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
65  if (licenseResponse == null) {
66  throw new InvalidLicenseException("License is null");
67  }
68 
69  DecryptedLicenseResponse decrypted = parseLicenseJSON(licenseResponse.getBoostLicense());
70  return new LicenseInfo(licenseResponse, decrypted);
71  }
72 
82  public DecryptedLicenseResponse parseLicenseJSON(BoostLicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
83  if (licenseResponse == null) {
84  throw new InvalidLicenseException("Boost license is null");
85  }
86 
87  String decryptedJsonResponse;
88  try {
89  decryptedJsonResponse = decryptLicenseString(
90  licenseResponse.getEncryptedJson(),
91  licenseResponse.getIv(),
92  licenseResponse.getEncryptedKey(),
93  licenseResponse.getVersion()
94  );
95  } catch (IOException | GeneralSecurityException ex) {
96  throw new InvalidLicenseException("An exception occurred while parsing the license string", ex);
97  }
98 
99  DecryptedLicenseResponse decryptedLicense = objectMapper.readValue(decryptedJsonResponse, DecryptedLicenseResponse.class);
100  if (!"AUTOPSY".equalsIgnoreCase(decryptedLicense.getProduct())) {
101  // license file is expected to contain product of "CYBERTRIAGE"
102  throw new InvalidLicenseException("Not a valid Autopsy license");
103  }
104 
105  return decryptedLicense;
106  }
107 
108  private String decryptLicenseString(String encryptedJson, String ivBase64, String encryptedKey, String version) throws IOException, GeneralSecurityException, InvalidLicenseException {
109  if (ObjectUtils.anyNull(encryptedJson, ivBase64, encryptedKey, version)) {
110  throw new InvalidLicenseException(MessageFormat.format(
111  "encryptedJson: {0}, iv: {1}, encryptedKey: {2}, version: {3} must all be non-null",
112  encryptedJson, ivBase64, encryptedKey, version));
113  }
114 
115  if (!"1.0".equals(version)) {
116  throw new InvalidLicenseException("Unexpected file version: " + version);
117  }
118 
119  byte[] encryptedKeyBytes = Base64.getDecoder().decode(encryptedKey);
120  byte[] keyBytes = decryptKey(encryptedKeyBytes);
121  SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");
122 
123  byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
124  IvParameterSpec iv = new IvParameterSpec(ivBytes);
125 
126  byte[] encryptedLicenseJsonBytes = Base64.getDecoder().decode(encryptedJson);
127 
128  String algorithm = "AES/CBC/PKCS5Padding";
129  Cipher cipher = Cipher.getInstance(algorithm);
130  cipher.init(Cipher.DECRYPT_MODE, key, iv);
131  byte[] licenseJsonBytes = cipher.doFinal(encryptedLicenseJsonBytes);
132 
133  return new String(licenseJsonBytes, StandardCharsets.UTF_8);
134  }
135 
136  private PublicKey getPublicKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
137 
138  String publicKeyString = """
139  -----BEGIN PUBLIC KEY-----
140  MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwIKulLyaLQ2WeO0gIW2G
141  3jQqny3Y/7VUevBKulAEywaUbvECvZ4zGsnaMyACjXxMNkA1xU2WeSMP/WqC03wz
142  4d71liUeAqOYKMdGHXFN2qswWz/ufK6An0pTEqYaoiUfcwSBVo2ZTUcMQexScKaS
143  ghmaWqBHBYx+lBkVMcLG2PtLDRZbqgJvJr2QCzMSVUpEGGQEWs7YolIq46KCgqsq
144  pTdfrdqd59x6oRhTLegswzxwLyouvrKbRqKR2ZRbVvlGtUnnnlLDuhEfd0flMxuv
145  W98Siw6dWe1K3x45nDu5py2G9Q9fZS8/2KHUC6QcLLstLIoPnZjCl9Lcur1U6s9N
146  f5aLI9mwMfmSJsoVOuwx2/MC98uHvPoPbG4ZjiT0aaGg4JccTGD6pssDA35zPhkk
147  1l6wktEYtyF2A7zjzuFxioQz8fHBzIbHPCxzu4S2gh3qOVFf7c9COmX9MsnB70o2
148  EZ1rxlFIJ7937IGJNwWOQuiMKTpEeT6BwTdQNZQPqCUGvZ5eEjhrm57yCF4zuyrt
149  AR8DG7ahK2YAarADHRyxTuxH1qY7E5/CTQKYk9tIYsV4O05CKj7B8rBMtjVNjb4b
150  d7JwPW43Z3J6jo/gLlVdGSPg8vQDNVLl6sdDM4Pm1eJEzgR2JlqXDCRDUGNNsXH2
151  qt9Ru8ykX7PAfF2Q3/qg1jkCAwEAAQ==
152  -----END PUBLIC KEY-----
153  """;
154 
155  publicKeyString = publicKeyString.replaceAll("-----BEGIN PUBLIC KEY-----", "").replaceAll("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");
156  byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
157 
158  KeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
159  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
160  PublicKey publicKey = keyFactory.generatePublic(keySpec);
161 
162  return publicKey;
163  }
164 
165  private byte[] decryptKey(byte[] encryptedKeyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
166 
167  PublicKey publicKey = getPublicKey();
168 
169  Cipher decryptCipher = Cipher.getInstance("RSA");
170  decryptCipher.init(Cipher.DECRYPT_MODE, publicKey);
171 
172  byte[] decryptedBytes = decryptCipher.doFinal(encryptedKeyBytes);
173 
174  return decryptedBytes;
175  }
176 
177  public class InvalidLicenseException extends Exception {
178 
179  public InvalidLicenseException(String message) {
180  super(message);
181  }
182 
183  public InvalidLicenseException(String message, Throwable cause) {
184  super(message, cause);
185  }
186 
187  }
188 }
DecryptedLicenseResponse parseLicenseJSON(BoostLicenseResponse licenseResponse)
String decryptLicenseString(String encryptedJson, String ivBase64, String encryptedKey, String version)

Copyright © 2012-2022 Basis Technology. Generated on: Tue Feb 6 2024
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.