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 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);
105
106 System.arraycopy(cipher.getIV(), 0, result, 0, 16);
107
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 }