View Javadoc
1   package org.metricshub.ipmi.core.coding.protocol.encoder;
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 org.metricshub.ipmi.core.coding.protocol.AuthenticationType;
26  import org.metricshub.ipmi.core.coding.protocol.IpmiMessage;
27  import org.metricshub.ipmi.core.coding.protocol.Ipmiv15Message;
28  import org.metricshub.ipmi.core.common.TypeConverter;
29  
30  import java.security.InvalidKeyException;
31  
32  /**
33   * Encodes IPMI v1.5 message
34   */
35  public class Protocolv15Encoder extends ProtocolEncoder {
36  
37  	/**
38  	 * @param ipmiMessage
39  	 *        - IPMI message to be encoded. Must be {@link Ipmiv15Message}.
40  	 * @throws InvalidKeyException
41  	 *         - when initiation of the confidentiality algorithm fails
42  	 * @throws IllegalArgumentException
43  	 *         when IPMI protocol version is incorrect.
44  	 * @see Ipmiv15Message
45  	 */
46  	@Override
47  	public byte[] encode(IpmiMessage ipmiMessage) throws InvalidKeyException {
48  		if (!(ipmiMessage instanceof Ipmiv15Message)) {
49  			throw new IllegalArgumentException("IPMIMessage must be in 1.5 version.");
50  		}
51  		Ipmiv15Message message = (Ipmiv15Message) ipmiMessage;
52  
53  		byte[] raw = new byte[getMessageLength(message)];
54  
55  		raw[0] = encodeAuthenticationType(message.getAuthenticationType());
56  
57  		int offset = 1;
58  
59  		encodeSessionSequenceNumber(message.getSessionSequenceNumber(), raw, offset);
60  		offset += 4;
61  
62  		encodeSessionId(message.getSessionID(), raw, offset);
63  		offset += 4;
64  
65  		if (message.getAuthenticationType() != AuthenticationType.None) {
66  			encodeAuthenticationCode(message.getAuthCode(), raw, offset);
67  			offset += message.getAuthCode().length;
68  		}
69  
70  		byte[] payload = message.getPayload().getEncryptedPayload();
71  
72  		if (payload == null) {
73  			message.getPayload().encryptPayload(message.getConfidentialityAlgorithm());
74  			payload = message.getPayload().getEncryptedPayload();
75  		}
76  
77  		encodePayloadLength(payload.length, raw, offset);
78  		++offset;
79  
80  		offset = encodePayload(payload, raw, offset);
81  
82  		encodeSessionTrailer(raw, offset);
83  
84  		return raw;
85  	}
86  
87  	private int getMessageLength(IpmiMessage ipmiMessage) {
88  		int length = 11
89  				+ ipmiMessage.getConfidentialityAlgorithm().getConfidentialityOverheadSize(ipmiMessage.getPayloadLength())
90  				+ ipmiMessage.getPayloadLength();
91  
92  		if (ipmiMessage.getAuthenticationType() != AuthenticationType.None) {
93  			length += 16;
94  		}
95  
96  		return length;
97  	}
98  
99  	/**
100 	 * Inserts authentication code into message at given offset.
101 	 *
102 	 * @param authCode
103 	 * @param message
104 	 *        - message being encoded
105 	 * @param offset
106 	 * @throws IndexOutOfBoundsException
107 	 *         when message is too short to hold value at given offset
108 	 */
109 	private void encodeAuthenticationCode(byte[] authCode, byte[] message, int offset) {
110 		if (authCode.length + offset > message.length) {
111 			throw new IndexOutOfBoundsException("Message is too short");
112 		}
113 		System.arraycopy(authCode, 0, message, offset, authCode.length);
114 	}
115 
116 	@Override
117 	protected void encodePayloadLength(int value, byte[] message, int offset) {
118 		message[offset] = TypeConverter.intToByte(value);
119 	}
120 
121 	/**
122 	 * Creates session trailer. <br>
123 	 * Creates an inserts Legacy PAD.
124 	 *
125 	 * @param message
126 	 *        - IPMI message being created
127 	 * @param offset
128 	 *        - Should point at the beginning of the session trailer.
129 	 * @throws IndexOutOfBoundsException
130 	 *         when message is too short to hold value at given offset
131 	 * @return Offset pointing after Authorization Code
132 	 */
133 	private int encodeSessionTrailer(byte[] message, int offset) {
134 		if (1 + offset > message.length) {
135 			throw new IndexOutOfBoundsException("Message is too short");
136 		}
137 
138 		message[offset] = 0;
139 
140 		return offset + 1;
141 	}
142 }