1 package org.metricshub.ipmi.core.coding.security;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
39
40 public class ConfidentialityAesCbc128 extends ConfidentialityAlgorithm {
41
42 private static final byte[] CONST2 = new byte[20];
43 static {
44 Arrays.fill(CONST2, (byte) 2);
45 }
46
47
48 private Cipher cipher;
49
50 private SecretKeySpec cipherKey;
51
52 @Override
53 public byte getCode() {
54 return SecurityConstants.CA_AES_CBC128;
55 }
56
57 @Override
58 public synchronized void initialize(byte[] sik, AuthenticationAlgorithm authenticationAlgorithm)
59 throws InvalidKeyException,
60 NoSuchAlgorithmException,
61 NoSuchPaddingException {
62 super.initialize(sik, authenticationAlgorithm);
63
64 final String algorithmName = authenticationAlgorithm.getAlgorithmName();
65 SecretKeySpec k2 = new SecretKeySpec(sik, algorithmName);
66
67 Mac mac = Mac.getInstance(algorithmName);
68 mac.init(k2);
69
70 byte[] ckey = mac.doFinal(CONST2);
71
72 byte[] ciphKey = new byte[16];
73
74 System.arraycopy(ckey, 0, ciphKey, 0, 16);
75
76 cipherKey = new SecretKeySpec(ciphKey, "AES");
77
78 cipher = Cipher.getInstance("AES/CBC/NoPadding");
79 }
80
81 @Override
82 public synchronized byte[] encrypt(byte[] data) throws InvalidKeyException {
83 int length = data.length + 17;
84 int pad = 0;
85 if (length % 16 != 0) {
86 pad = 16 - length % 16;
87 }
88 length += pad;
89
90 byte[] result = new byte[length - 16];
91
92 cipher.init(Cipher.ENCRYPT_MODE, cipherKey);
93
94 System.arraycopy(data, 0, result, 0, data.length);
95
96 for (int i = 0; i < pad; ++i) {
97 result[i + data.length] = TypeConverter.intToByte(i + 1);
98 }
99
100 result[length - 17] = TypeConverter.intToByte(pad);
101
102 try {
103 byte[] encrypted = cipher.doFinal(result);
104
105 result = new byte[encrypted.length + 16];
106
107 System.arraycopy(encrypted, 0, result, 16, encrypted.length);
108
109 System.arraycopy(cipher.getIV(), 0, result, 0, 16);
110
111
112 return result;
113 } catch (Exception e) {
114 throw new IllegalArgumentException(e.getMessage(), e);
115 }
116 }
117
118 @Override
119 public synchronized byte[] decrypt(byte[] data) {
120
121 byte[] decrypted = null;
122 try {
123 byte[] iv = new byte[16];
124
125 System.arraycopy(data, 0, iv, 0, 16);
126
127 byte[] encrypted = new byte[data.length - 16];
128
129 System.arraycopy(data, 16, encrypted, 0, encrypted.length);
130
131 cipher.init(Cipher.DECRYPT_MODE, cipherKey, new IvParameterSpec(iv));
132 decrypted = cipher.doFinal(encrypted);
133 } catch (Exception e) {
134 throw new IllegalArgumentException("Decryption failed", e);
135 }
136
137
138 int pad = decrypted.length == 0 ? -1 : TypeConverter.byteToInt(decrypted[decrypted.length - 1]);
139 if (pad < 0 || pad > 15 || pad >= decrypted.length) {
140 throw new IllegalArgumentException("Invalid confidentiality pad length");
141 }
142 int length = decrypted.length - pad - 1;
143 for (int i = 0; i < pad; ++i) {
144 if (TypeConverter.byteToInt(decrypted[length + i]) != i + 1) {
145 throw new IllegalArgumentException("Invalid confidentiality pad");
146 }
147 }
148
149 return Arrays.copyOf(decrypted, length);
150 }
151
152 @Override
153 public int getConfidentialityOverheadSize(int payloadSize) {
154 int size = 17;
155 if ((size + payloadSize) % 16 != 0) {
156 size += 16 - (size + payloadSize) % 16;
157 }
158 return size;
159 }
160
161 }