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(
50                      "IPMIMessage must be in 1.5 version.");
51          }
52          Ipmiv15Message message = (Ipmiv15Message) ipmiMessage;
53  
54          byte[] raw = new byte[getMessageLength(message)];
55  
56          raw[0] = encodeAuthenticationType(message.getAuthenticationType());
57  
58          int offset = 1;
59  
60          encodeSessionSequenceNumber(message.getSessionSequenceNumber(), raw,
61                  offset);
62          offset += 4;
63  
64          encodeSessionId(message.getSessionID(), raw, offset);
65          offset += 4;
66  
67          if (message.getAuthenticationType() != AuthenticationType.None) {
68              encodeAuthenticationCode(message.getAuthCode(), raw, offset);
69              offset += message.getAuthCode().length;
70          }
71  
72          byte[] payload = message.getPayload().getEncryptedPayload();
73  
74          if (payload == null) {
75              message.getPayload().encryptPayload(
76                      message.getConfidentialityAlgorithm());
77              payload = message.getPayload().getEncryptedPayload();
78          }
79  
80          encodePayloadLength(payload.length, raw, offset);
81          ++offset;
82  
83          offset = encodePayload(payload, raw, offset);
84  
85          encodeSessionTrailer(raw, offset);
86  
87          return raw;
88      }
89  
90      private int getMessageLength(IpmiMessage ipmiMessage) {
91          int length = 11
92                  + ipmiMessage.getConfidentialityAlgorithm()
93                          .getConfidentialityOverheadSize(
94                                  ipmiMessage.getPayloadLength())
95                  + ipmiMessage.getPayloadLength();
96  
97          if (ipmiMessage.getAuthenticationType() != AuthenticationType.None) {
98              length += 16;
99          }
100 
101         return length;
102     }
103 
104     /**
105      * Inserts authentication code into message at given offset.
106      *
107      * @param authCode
108      * @param message
109      *            - message being encoded
110      * @param offset
111      * @throws IndexOutOfBoundsException
112      *             when message is too short to hold value at given offset
113      */
114     private void encodeAuthenticationCode(byte[] authCode, byte[] message, int offset) {
115         if (authCode.length + offset > message.length) {
116             throw new IndexOutOfBoundsException("Message is too short");
117         }
118         System.arraycopy(authCode, 0, message, offset, authCode.length);
119     }
120 
121     @Override
122     protected void encodePayloadLength(int value, byte[] message, int offset) {
123         message[offset] = TypeConverter.intToByte(value);
124     }
125 
126     /**
127      * Creates session trailer. <br>
128      * Creates an inserts Legacy PAD.
129      *
130      * @param message
131      *            - IPMI message being created
132      * @param offset
133      *            - Should point at the beginning of the session trailer.
134      * @throws IndexOutOfBoundsException
135      *             when message is too short to hold value at given offset
136      * @return Offset pointing after Authorization Code
137      */
138     private int encodeSessionTrailer(byte[] message, int offset) {
139         if (1 + offset > message.length) {
140             throw new IndexOutOfBoundsException("Message is too short");
141         }
142 
143         message[offset] = 0;
144 
145         return offset + 1;
146     }
147 }