Autopsy  4.20.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.util.Base64;
38 import javax.crypto.BadPaddingException;
39 import javax.crypto.Cipher;
40 import javax.crypto.IllegalBlockSizeException;
41 import javax.crypto.NoSuchPaddingException;
42 import javax.crypto.SecretKey;
43 import javax.crypto.spec.IvParameterSpec;
44 import javax.crypto.spec.SecretKeySpec;
45 
49 public class LicenseDecryptorUtil {
50 
51  private static final LicenseDecryptorUtil instance = new LicenseDecryptorUtil();
52 
54  return instance;
55  }
56 
58 
60  }
61 
62  public LicenseInfo createLicenseInfo(LicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
63  if (licenseResponse == null || licenseResponse.getBoostLicense() == null) {
64  throw new InvalidLicenseException("License or boost license are null");
65  }
66 
67  DecryptedLicenseResponse decrypted = parseLicenseJSON(licenseResponse.getBoostLicense());
68  return new LicenseInfo(licenseResponse, decrypted);
69  }
70 
80  public DecryptedLicenseResponse parseLicenseJSON(BoostLicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
81 
82  String decryptedJsonResponse;
83  try {
84  decryptedJsonResponse = decryptLicenseString(
85  licenseResponse.getEncryptedJson(),
86  licenseResponse.getIv(),
87  licenseResponse.getEncryptedKey(),
88  licenseResponse.getVersion()
89  );
90  } catch (IOException | GeneralSecurityException ex) {
91  throw new InvalidLicenseException("An exception occurred while parsing the license string", ex);
92  }
93 
94  DecryptedLicenseResponse decryptedLicense = objectMapper.readValue(decryptedJsonResponse, DecryptedLicenseResponse.class);
95  if (!"AUTOPSY".equalsIgnoreCase(decryptedLicense.getProduct())) {
96  // license file is expected to contain product of "CYBERTRIAGE"
97  throw new InvalidLicenseException("Not a valid Autopsy license");
98  }
99 
100  return decryptedLicense;
101  }
102 
103  private String decryptLicenseString(String encryptedJson, String ivBase64, String encryptedKey, String version) throws IOException, GeneralSecurityException, InvalidLicenseException {
104  if (!"1.0".equals(version)) {
105  throw new InvalidLicenseException("Unexpected file version: " + version);
106  }
107 
108  byte[] encryptedKeyBytes = Base64.getDecoder().decode(encryptedKey);
109  byte[] keyBytes = decryptKey(encryptedKeyBytes);
110  SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");
111 
112  byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
113  IvParameterSpec iv = new IvParameterSpec(ivBytes);
114 
115  byte[] encryptedLicenseJsonBytes = Base64.getDecoder().decode(encryptedJson);
116 
117  String algorithm = "AES/CBC/PKCS5Padding";
118  Cipher cipher = Cipher.getInstance(algorithm);
119  cipher.init(Cipher.DECRYPT_MODE, key, iv);
120  byte[] licenseJsonBytes = cipher.doFinal(encryptedLicenseJsonBytes);
121 
122  return new String(licenseJsonBytes, StandardCharsets.UTF_8);
123  }
124 
125  private PublicKey getPublicKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
126 
127  String publicKeyString = """
128  -----BEGIN PUBLIC KEY-----
129  MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwIKulLyaLQ2WeO0gIW2G
130  3jQqny3Y/7VUevBKulAEywaUbvECvZ4zGsnaMyACjXxMNkA1xU2WeSMP/WqC03wz
131  4d71liUeAqOYKMdGHXFN2qswWz/ufK6An0pTEqYaoiUfcwSBVo2ZTUcMQexScKaS
132  ghmaWqBHBYx+lBkVMcLG2PtLDRZbqgJvJr2QCzMSVUpEGGQEWs7YolIq46KCgqsq
133  pTdfrdqd59x6oRhTLegswzxwLyouvrKbRqKR2ZRbVvlGtUnnnlLDuhEfd0flMxuv
134  W98Siw6dWe1K3x45nDu5py2G9Q9fZS8/2KHUC6QcLLstLIoPnZjCl9Lcur1U6s9N
135  f5aLI9mwMfmSJsoVOuwx2/MC98uHvPoPbG4ZjiT0aaGg4JccTGD6pssDA35zPhkk
136  1l6wktEYtyF2A7zjzuFxioQz8fHBzIbHPCxzu4S2gh3qOVFf7c9COmX9MsnB70o2
137  EZ1rxlFIJ7937IGJNwWOQuiMKTpEeT6BwTdQNZQPqCUGvZ5eEjhrm57yCF4zuyrt
138  AR8DG7ahK2YAarADHRyxTuxH1qY7E5/CTQKYk9tIYsV4O05CKj7B8rBMtjVNjb4b
139  d7JwPW43Z3J6jo/gLlVdGSPg8vQDNVLl6sdDM4Pm1eJEzgR2JlqXDCRDUGNNsXH2
140  qt9Ru8ykX7PAfF2Q3/qg1jkCAwEAAQ==
141  -----END PUBLIC KEY-----
142  """;
143 
144  publicKeyString = publicKeyString.replaceAll("-----BEGIN PUBLIC KEY-----", "").replaceAll("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");
145  byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
146 
147  KeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
148  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
149  PublicKey publicKey = keyFactory.generatePublic(keySpec);
150 
151  return publicKey;
152  }
153 
154  private byte[] decryptKey(byte[] encryptedKeyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
155 
156  PublicKey publicKey = getPublicKey();
157 
158  Cipher decryptCipher = Cipher.getInstance("RSA");
159  decryptCipher.init(Cipher.DECRYPT_MODE, publicKey);
160 
161  byte[] decryptedBytes = decryptCipher.doFinal(encryptedKeyBytes);
162 
163  return decryptedBytes;
164  }
165 
166  public class InvalidLicenseException extends Exception {
167 
168  public InvalidLicenseException(String message) {
169  super(message);
170  }
171 
172  public InvalidLicenseException(String message, Throwable cause) {
173  super(message, cause);
174  }
175 
176  }
177 }
DecryptedLicenseResponse parseLicenseJSON(BoostLicenseResponse licenseResponse)
String decryptLicenseString(String encryptedJson, String ivBase64, String encryptedKey, String version)

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