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 }