View Javadoc
1   package org.metricshub.ipmi.core.coding.security;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * IPMI Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 Verax Systems, MetricsHub
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23   */
24  
25  import java.security.InvalidKeyException;
26  import java.security.NoSuchAlgorithmException;
27  import java.util.Arrays;
28  
29  import javax.crypto.Cipher;
30  import javax.crypto.Mac;
31  import javax.crypto.NoSuchPaddingException;
32  import javax.crypto.spec.IvParameterSpec;
33  import javax.crypto.spec.SecretKeySpec;
34  
35  import org.metricshub.ipmi.core.common.TypeConverter;
36  
37  /**
38   * AES-CBC-128 confidentiality algorithm
39   */
40  public class ConfidentialityAesCbc128 extends ConfidentialityAlgorithm {
41  
42  	protected static final byte[] CONST2 = new byte[20];
43  	static {
44  		Arrays.fill(CONST2, (byte) 2);
45  	}
46  
47      private Cipher cipher;
48  
49      private SecretKeySpec cipherKey;
50  
51      @Override
52      public byte getCode() {
53          return SecurityConstants.CA_AES_CBC128;
54      }
55  
56      @Override
57      public void initialize(byte[] sik, AuthenticationAlgorithm authenticationAlgorithm) throws InvalidKeyException,
58              NoSuchAlgorithmException, NoSuchPaddingException {
59          super.initialize(sik, authenticationAlgorithm);
60  
61          final String algorithmName = authenticationAlgorithm.getAlgorithmName();
62  		SecretKeySpec k2 = new SecretKeySpec(sik, algorithmName);
63  
64          Mac mac = Mac.getInstance(algorithmName);
65          mac.init(k2);
66  
67          byte[] ckey = mac.doFinal(CONST2);
68  
69          byte[] ciphKey = new byte[16];
70  
71          System.arraycopy(ckey, 0, ciphKey, 0, 16);
72  
73          cipherKey = new SecretKeySpec(ciphKey, "AES");
74  
75          cipher = Cipher.getInstance("AES/CBC/NoPadding");
76      }
77  
78      @Override
79      public byte[] encrypt(byte[] data) throws InvalidKeyException {
80          int length = data.length + 17;
81          int pad = 0;
82          if (length % 16 != 0) {
83              pad = 16 - length % 16;
84          }
85          length += pad;
86  
87          byte[] result = new byte[length - 16];
88  
89          cipher.init(Cipher.ENCRYPT_MODE, cipherKey);
90  
91          System.arraycopy(data, 0, result, 0, data.length);
92  
93          for (int i = 0; i < pad; ++i) {
94              result[i + data.length] = TypeConverter.intToByte(i + 1);
95          }
96  
97          result[length - 17] = TypeConverter.intToByte(pad);
98  
99          try {
100             byte[] encrypted = cipher.doFinal(result);
101 
102             result = new byte[encrypted.length + 16];
103 
104             System.arraycopy(encrypted, 0, result, 16, encrypted.length); // encrypted
105                                                                             // payload
106             System.arraycopy(cipher.getIV(), 0, result, 0, 16); // Initialization
107                                                                 // vector
108 
109             return result;
110         } catch (Exception e) {
111             throw new IllegalArgumentException(e.getMessage(), e);
112         }
113     }
114 
115     @Override
116     public byte[] decrypt(byte[] data) {
117 
118         byte[] decrypted = null;
119         try {
120             byte[] iv = new byte[16];
121 
122             System.arraycopy(data, 0, iv, 0, 16);
123 
124             byte[] encrypted = new byte[data.length - 16];
125 
126             System.arraycopy(data, 16, encrypted, 0, encrypted.length);
127 
128             cipher.init(Cipher.DECRYPT_MODE, cipherKey, new IvParameterSpec(iv));
129             decrypted = cipher.doFinal(encrypted);
130         } catch (Exception e) {
131             throw new IllegalArgumentException("Decryption failed", e);
132         }
133 
134         int pad = TypeConverter.byteToInt(decrypted[decrypted.length - 1]);
135 
136         byte[] result = new byte[decrypted.length - pad - 1];
137 
138         System.arraycopy(decrypted, 0, result, 0, result.length);
139 
140         return result;
141     }
142 
143     @Override
144     public int getConfidentialityOverheadSize(int payloadSize) {
145         int size = 17;
146         if ((size + payloadSize) % 16 != 0) {
147             size += 16 - (size + payloadSize) % 16;
148         }
149         return size;
150     }
151 
152 }