001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.security; 020 021import java.io.PrintStream; 022import java.util.Collections; 023import java.util.LinkedHashMap; 024import java.util.Map; 025import java.util.Map.Entry; 026import org.jpos.iso.ISOUtil; 027 028/** 029 * The class represents a secure key in key block form (TR-31 or derivatives). 030 * <p> 031 * In addition to standard Key Chcek Value and Key Schema, specifies the key 032 * block header, optional key block header, encrypted key and key block MAC. 033 * <p> 034 * The {@code SecureKeyBlock} instance can come from HSM <i>(generate, import, 035 * translate)</i> or from the key store. And this is an integral whole. 036 * Therefore, manipulation of key block values is not desirable. This is the 037 * reason why the key block setters methods are not available. Use the 038 * {@code SecureKeyBlockBuilder} to create the key block structure. 039 */ 040public class SecureKeyBlock extends SecureKey { 041 042 /** 043 * Identifies the method by which the key block is cryptographically 044 * protected and the content layout of the block. 045 */ 046 protected char keyBlockVersion = ' '; 047 048 /** 049 * Entire key block length after encoding (header, optional header, 050 * encrypted confidential data, and MAC). 051 */ 052 protected int keyBlockLength; 053 054 /** 055 * The primary usage of the key contained in the key block. 056 */ 057 protected KeyUsage keyUsage; 058 059 /** 060 * The cryptographic algorithm with which the key contained in key block 061 * will be used. 062 */ 063 protected Algorithm algorithm = Algorithm.TDES; 064 065 /** 066 * The operation that the key contained in the key block can perform. 067 */ 068 protected ModeOfUse modeOfUse = ModeOfUse.ANY; 069 070 /** 071 * Version number to optionally indicate that the contents of the key block 072 * is a component (key part), or to prevent re-injection of an old key. 073 */ 074 protected String keyVersion = " "; 075 076 /** 077 * The conditions under which the key can be exported outside the 078 * cryptographic domain. 079 */ 080 protected Exportability exportability = Exportability.ANY; 081 082 /** 083 * This element is not specified by TR-31 (should contain two ASCII zeros). 084 * <p> 085 * In proprietary derivatives can be used as e.g: LMK identifier. 086 */ 087 protected String reserved = "00"; 088 089 /** 090 * The TR-31 Key Block format allows a key block to contain up to 99 091 * Optional Header Blocks which can be used to include additional (optional) 092 * data within the Key Block. 093 */ 094 protected Map<String, String> optionalHeaders = new LinkedHashMap<>(); 095 096 /** 097 * The key block MAC ensures the integrity of the key block, and is 098 * calculated over the Header, Optional Header Blocks and the encrypted Key 099 * Data. 100 */ 101 protected byte[] keyBlockMAC; 102 103 /** 104 * Constructs an SecureKeyBlock. 105 * <p> 106 * It can be used internally by e.g: {@code SecureKeyBlockBuilder}. 107 */ 108 protected SecureKeyBlock() { 109 super(); 110 } 111 112 @Override 113 public void setKeyType(String keyType) { 114 throw new UnsupportedOperationException( 115 "Operation setKeyType() not allowed for " + SecureKeyBlock.class.getName() 116 ); 117 } 118 119 @Override 120 public String getKeyType() { 121 throw new UnsupportedOperationException( 122 "Operation getKeyType() not allowed for " + SecureKeyBlock.class.getName() 123 ); 124 } 125 126 @Override 127 public void setKeyLength(short keyLength) { 128 throw new UnsupportedOperationException( 129 "Operation setKeyLength() not allowed for " + SecureKeyBlock.class.getName() 130 ); 131 } 132 133 @Override 134 public short getKeyLength() { 135 throw new UnsupportedOperationException( 136 "Operation getKeyLength() not allowed for " + SecureKeyBlock.class.getName() 137 ); 138 } 139 140 @Override 141 public KeyScheme getScheme() { 142 return scheme; 143 } 144 145 /** 146 * Identifies the method by which the key block is cryptographically 147 * protected and the content layout of the block. 148 * 149 * @return The key block version that corresponds to byte 0 of the key block. 150 */ 151 public char getKeyBlockVersion() { 152 return keyBlockVersion; 153 } 154 155 /** 156 * Entire key block length after encoding (header, optional header, 157 * encrypted confidential data, and MAC). 158 * 159 * @return The key block length that corresponds to bytes 1-4 of the key block. 160 */ 161 public int getKeyBlockLength() { 162 return keyBlockLength; 163 } 164 165 /** 166 * The primary usage of the key contained in the key block. 167 * 168 * @return The key usage that corresponds to bytes 5-6 of the key block. 169 */ 170 public KeyUsage getKeyUsage() { 171 return keyUsage; 172 } 173 174 /** 175 * The cryptographic algorithm with which the key contained in key block 176 * will be used. 177 * 178 * @return The key algorithm that corresponds to byte 7 of the key block. 179 */ 180 public Algorithm getAlgorithm() { 181 return algorithm; 182 } 183 184 /** 185 * The operation that the key contained in the key block can perform. 186 * 187 * @return The mode of use that corresponds to byte 8 of the key block. 188 */ 189 public ModeOfUse getModeOfUse() { 190 return modeOfUse; 191 } 192 193 /** 194 * Version number to optionally indicate that the contents of the key block 195 * is a component (key part), or to prevent re-injection of an old key. 196 * 197 * @return The key version that corresponds to bytes 9-10 of the key block. 198 */ 199 public String getKeyVersion() { 200 return keyVersion; 201 } 202 203 /** 204 * The conditions under which the key can be exported outside the 205 * cryptographic domain. 206 * 207 * @return The key exportability that corresponds to byte 11 of the key block. 208 */ 209 public Exportability getExportability() { 210 return exportability; 211 } 212 213 /** 214 * This element is not specified by TR-31 (should contain two ASCII zeros). 215 * <p> 216 * In proprietary derivatives can be used as e.g: LMK identifier. 217 * 218 * @return The reserved that corresponds to bytes 14-15 of the key block. 219 */ 220 public String getReserved() { 221 return reserved; 222 } 223 224 /** 225 * The key blok Optional Header Blocks. 226 * <p> 227 * The number of optional heders corresponds to bytes 12-13 of the key block. 228 * <p> 229 * The order of the elements in the map is preserved by {@code LinkedHashMap} 230 * 231 * @return Read only map of Optional Key Blok Heders. 232 */ 233 public Map<String, String> getOptionalHeaders() { 234 return Collections.unmodifiableMap(optionalHeaders); 235 } 236 237 /** 238 * The key block MAC ensures the integrity of the key block. 239 * <p> 240 * It is calculated over the Header, Optional Header Blocks and the 241 * encrypted Key Data. 242 * The length of the MAC depends on the type of LMK key: 243 * <ul> 244 * <li>4 bytes for DES Key Block LMK 245 * <li>8 bytes for AES Key Block LMK 246 * </ul> 247 * 248 * @return calculated key block MAC value. 249 */ 250 public byte[] getKeyBlockMAC() { 251 return keyBlockMAC; 252 } 253 254 /** 255 * Dumps SecureKeyBlock basic information 256 * 257 * @param p a PrintStream usually supplied by Logger 258 * @param indent indention string, usually suppiled by Logger 259 * @see org.jpos.util.Loggeable 260 */ 261 @Override 262 public void dump(PrintStream p, String indent) { 263 String inner = indent + " "; 264 String inner2 = inner + " "; 265 p.print(indent + "<secure-key-block"); 266 p.print(" scheme=\"" + scheme + "\""); 267 if (keyName != null) 268 p.print(" name=\"" + keyName + "\""); 269 270 p.println(">"); 271 272 p.println(inner + "<header>"); 273 p.println(inner2 + "<version>" + keyBlockVersion + "</version>"); 274 p.println(inner2 + "<key-usage>" + keyUsage.getCode() + "</key-usage>"); 275 p.println(inner2 + "<algorithm>" + algorithm.getCode() + "</algorithm>"); 276 p.println(inner2 + "<mode-of-use>" + modeOfUse.getCode() + "</mode-of-use>"); 277 p.println(inner2 + "<key-version>" + keyVersion + "</key-version>"); 278 p.println(inner2 + "<exportability>" + exportability.getCode() + "</exportability>"); 279 if (reserved != null && !"00".equals(reserved)) 280 p.println(inner2 + "<reserved>" + reserved + "</reserved>"); 281 p.println(inner + "</header>"); 282 283 if (!optionalHeaders.isEmpty()) { 284 p.println(inner + "<optional-header>"); 285 for (Entry<String, String> ent : optionalHeaders.entrySet()) 286 p.println(inner2 + "<entry id=\""+ ent.getKey() + "\" value=\""+ ent.getValue()+ "\"/>"); 287 p.println(inner + "</optional-header>"); 288 } 289 290 p.println(inner + "<data>" + ISOUtil.hexString(getKeyBytes()) + "</data>"); 291 p.println(inner + "<mac>" + ISOUtil.hexString(getKeyBlockMAC()) + "</mac>"); 292 if (getKeyCheckValue() != null) 293 p.println(inner + "<check-value>" + ISOUtil.hexString(getKeyCheckValue()) + "</check-value>"); 294 p.println(indent + "</secure-key-block>"); 295 } 296 297}