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.Mac;
30  import javax.crypto.spec.SecretKeySpec;
31  
32  import org.metricshub.ipmi.core.coding.commands.session.Rakp1;
33  
34  /**
35   * Interface for authentication algorithms. All classes extending this one must
36   * have a parameterless constructor.
37   */
38  public abstract class AuthenticationAlgorithm {
39  
40  	private final Mac mac;
41  
42  	/**
43  	 * Constructs an authentication algorithm.
44  	 */
45  	protected AuthenticationAlgorithm(String algorithmName) {
46  		this(CipherSuite.newMacInstance(algorithmName));
47  	}
48  
49  	/**
50  	 * Constructs an authentication algorithm with the provided MAC.
51  	 *
52  	 * @param mac the MAC instance to use
53  	 */
54  	private AuthenticationAlgorithm(Mac mac) {
55  		this.mac = mac;
56  	}
57  
58  	/**
59  	 * @return algorithm-specific code
60  	 */
61  	public abstract byte getCode();
62  
63  	/**
64  	 * @return length of the key for the RAKP2 message
65  	 */
66  	public abstract int getKeyLength();
67  
68  	/**
69  	 * @return length of the integrity check base for RAKP4 message
70  	 */
71  	public abstract int getIntegrityCheckBaseLength();
72  
73  	/**
74  	 * Checks value of the Key Exchange Authentication Code in RAKP messages
75  	 *
76  	 * @param data     - The base for authentication algorithm. Depends on RAKP
77  	 *                 Message.
78  	 * @param key      - the Key Exchange Authentication Code to check.
79  	 * @param password - password of the user establishing a session
80  	 * @return True if authentication check was successful, false otherwise.
81  	 * @throws NoSuchAlgorithmException when initiation of the algorithm fails
82  	 * @throws InvalidKeyException      when creating of the algorithm key fails
83  	 */
84  	public boolean checkKeyExchangeAuthenticationCode(byte[] data, byte[] key, String password)
85  			throws NoSuchAlgorithmException, InvalidKeyException {
86  		byte[] check = getKeyExchangeAuthenticationCode(data, password);
87  		return Arrays.equals(check, key);
88  	}
89  
90  	/**
91  	 * Calculates value of the Key Exchange Authentication Code in RAKP messages
92  	 *
93  	 * @param data     - The base for authentication algorithm. Depends on RAKP
94  	 *                 Message.
95  	 * @param password - password of the user establishing a session
96  	 * @throws NoSuchAlgorithmException when initiation of the algorithm fails
97  	 * @throws InvalidKeyException      when creating of the algorithm key fails
98  	 */
99  	public byte[] getKeyExchangeAuthenticationCode(byte[] data, String password)
100 			throws NoSuchAlgorithmException, InvalidKeyException {
101 
102 		final byte[] key = password.getBytes();
103 
104 		SecretKeySpec sKey = new SecretKeySpec(key, getAlgorithmName());
105 		mac.init(sKey);
106 
107 		return mac.doFinal(data);
108 	}
109 
110 	/**
111 	 * Validates Integrity Check Value in RAKP Message 4.
112 	 *
113 	 * @param data      - The base for authentication algorithm.
114 	 * @param reference - The Integrity Check Value to validate.
115 	 * @param sik       - The Session Integrity Key generated on base of RAKP
116 	 *                  Messages 1 and 2.
117 	 * @see Rakp1#calculateSik(org.metricshub.ipmi.core.coding.commands.session.Rakp1ResponseData)
118 	 * @return True if integrity check was successful, false otherwise.
119 	 * @throws NoSuchAlgorithmException when initiation of the algorithm fails
120 	 * @throws InvalidKeyException      when creating of the algorithm key fails
121 	 */
122 	public boolean doIntegrityCheck(byte[] data, byte[] reference, byte[] sik)
123 			throws InvalidKeyException, NoSuchAlgorithmException {
124 
125 		SecretKeySpec sKey = new SecretKeySpec(sik, getAlgorithmName());
126 		mac.init(sKey);
127 		
128 		final int integrityCheckLength = getIntegrityCheckBaseLength();
129 		final byte[] result = new byte[integrityCheckLength];
130 
131 		System.arraycopy(mac.doFinal(data), 0, result, 0, integrityCheckLength);
132 
133 		return Arrays.equals(result, reference);
134 	}
135 
136 	/**
137 	 * @return the name of the algorithm as a {@code String}.
138 	 */
139 	public abstract String getAlgorithmName();
140 }