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.ByteArrayOutputStream; 022import java.io.IOException; 023import java.io.PrintStream; 024import org.jpos.util.Loggeable; 025 026import java.io.Serializable; 027import java.util.LinkedHashMap; 028import java.util.Map; 029import java.util.Map.Entry; 030import org.jpos.iso.ISOUtil; 031 032/** 033 * This class contains a set of desirable key properties that can be passed to 034 * an HSM device for example to generate a key or import it. 035 * <p> 036 * This class is not intended to use for key storage. It can contain 037 * confidentional data like key length. That is why they should not be kept 038 * persistently anywhere. 039 * 040 * @author Robert Demski 041 */ 042public class SecureKeySpec 043 implements Serializable, Loggeable { 044 045 private static final long serialVersionUID = -3145281298749096305L; 046 047 /** 048 * Key scheme indicates protection metchod appiled to this key by 049 * a security module. 050 */ 051 protected KeyScheme scheme; 052 053 /** 054 * The key length is expressed in bits and refers to clear key <i>(before 055 * LMK protection)</i>. 056 */ 057 protected int keyLength; 058 059 /** 060 * Key Type is useful for stating what this key can be used for. 061 * <p> 062 * The value of Key Type specifies whether this encryped key is a 063 * <ul> 064 * <li>{@link SMAdapter#TYPE_TMK} Terminal Master Key 065 * <li>{@link SMAdapter#TYPE_ZPK} Zone PIN Key 066 * <li>or others 067 * </ul> 068 */ 069 protected String keyType; 070 071 /** 072 * Indicates key protection variant metchod appiled to this key by a security module. 073 */ 074 protected int variant; 075 076 /** 077 * Secure Key Bytes. 078 */ 079 protected byte[] keyBytes = null; 080 081 /** 082 * The keyCheckValue allows identifying which clear key does this 083 * secure key represent. 084 */ 085 protected byte[] keyCheckValue; 086 087 /** 088 * Identifies the method by which the key block is cryptographically 089 * protected and the content layout of the block. 090 */ 091 protected char keyBlockVersion; 092 093 /** 094 * The primary usage of the key contained in the key block. 095 */ 096 protected KeyUsage keyUsage; 097 098 /** 099 * The cryptographic algorithm with which the key contained in key block 100 * will be used. 101 */ 102 protected Algorithm algorithm; 103 104 /** 105 * The operation that the key contained in the key block can perform. 106 */ 107 protected ModeOfUse modeOfUse; 108 109 /** 110 * Version number to optionally indicate that the contents of the key block 111 * is a component (key part), or to prevent re-injection of an old key. 112 */ 113 protected String keyVersion; 114 115 /** 116 * The conditions under which the key can be exported outside the 117 * cryptographic domain. 118 */ 119 protected Exportability exportability; 120 121 /** 122 * This element is not specified by TR-31 (should contain two ASCII zeros). 123 * <p> 124 * In proprietary derivatives can be used as e.g: LMK identifier. 125 */ 126 protected String reserved; 127 128 /** 129 * The TR-31 Key Block format allows a key block to contain up to 99 130 * Optional Header Blocks which can be used to include additional (optional) 131 * data within the Key Block. 132 */ 133 protected final Map<String, String> optionalHeaders = new LinkedHashMap<>(); 134 135 /** 136 * The key block MAC ensures the integrity of the key block, and is 137 * calculated over the Header, Optional Header Blocks and the encrypted Key 138 * Data. 139 */ 140 protected byte[] keyBlockMAC; 141 142 /** 143 * Optional key name. 144 */ 145 protected String keyName; 146 147 public SecureKeySpec() { 148 super(); 149 } 150 151 /** 152 * Key scheme indicates protection metchod appiled to this key by 153 * the security module. 154 * 155 * @param scheme key scheme used to protect this key. 156 */ 157 public void setScheme(KeyScheme scheme) { 158 this.scheme = scheme; 159 } 160 161 /** 162 * Gets the key scheme used to protect this key. 163 * 164 * @return key scheme used to protect this key. 165 */ 166 public KeyScheme getScheme() { 167 return scheme; 168 } 169 170 /** 171 * Sets the length of the key. 172 * <p> 173 * The key length is expressed in bits and refers to clear key <i>(before 174 * LMK protection)</i> 175 * This might be different than the bit length of the secureKeyBytes. 176 * 177 * @param keyLength 178 */ 179 public void setKeyLength(int keyLength) { 180 this.keyLength = keyLength; 181 } 182 183 /** 184 * Gets the length of the key. 185 * <p> 186 * The key length is expressed in bits and refers to clear key <i>(before 187 * LMK protection)</i> 188 * 189 * @return The length of the clear key 190 */ 191 public int getKeyLength() { 192 return keyLength; 193 } 194 195 /** 196 * Key Type is useful for stating what this key can be used for. 197 * <p> 198 * The value of Key Type specifies whether this secure key is a 199 * <ul> 200 * <li>{@link SMAdapter#TYPE_TMK} Terminal Master Key 201 * <li>{@link SMAdapter#TYPE_ZPK} Zone PIN Key 202 * <li>or others 203 * </ul> 204 * 205 * @param keyType type of the key 206 */ 207 public void setKeyType(String keyType) { 208 this.keyType = keyType; 209 } 210 211 /** 212 * Key Type is useful for stating what this key can be used for. 213 * <p> 214 * The value of Key Type specifies whether this secure key is a 215 * <ul> 216 * <li>{@link SMAdapter#TYPE_TMK} Terminal Master Key 217 * <li>{@link SMAdapter#TYPE_ZPK} Zone PIN Key 218 * <li>or others 219 * </ul> 220 * 221 * @return keyType type of the key 222 */ 223 public String getKeyType() { 224 return this.keyType; 225 } 226 227 /** 228 * Sets key protection variant metchod appiled to this key by the security module. 229 * 230 * @param variant key variant method used to protect this key. 231 */ 232 public void setVariant(int variant) { 233 this.variant = variant; 234 } 235 236 /** 237 * Gets the key variant method used to protect this key. 238 * 239 * @return key variant method used to protect this key. 240 */ 241 public int getVariant() { 242 return this.variant; 243 } 244 245 /** 246 * Identifies the method by which the key block is cryptographically 247 * protected and the content layout of the block. 248 * 249 * @return The key block version that corresponds to byte 0 of the key block. 250 */ 251 public char getKeyBlockVersion() { 252 return keyBlockVersion; 253 } 254 255 public void setKeyBlockVersion(char keyBlockVersion) { 256 this.keyBlockVersion = keyBlockVersion; 257 } 258 259 /** 260 * The primary usage of the key contained in the key block. 261 * 262 * @return The key usage that corresponds to bytes 5-6 of the key block. 263 */ 264 public KeyUsage getKeyUsage() { 265 return keyUsage; 266 } 267 268 public void setKeyUsage(KeyUsage keyUsage) { 269 this.keyUsage = keyUsage; 270 } 271 272 /** 273 * The cryptographic algorithm with which the key contained in key block 274 * will be used. 275 * 276 * @return The key algorithm that corresponds to byte 7 of the key block. 277 */ 278 public Algorithm getAlgorithm() { 279 return algorithm; 280 } 281 282 public void setAlgorithm(Algorithm algorithm) { 283 this.algorithm = algorithm; 284 } 285 286 /** 287 * The operation that the key contained in the key block can perform. 288 * 289 * @return The mode of use that corresponds to byte 8 of the key block. 290 */ 291 public ModeOfUse getModeOfUse() { 292 return modeOfUse; 293 } 294 295 public void setModeOfUse(ModeOfUse modeOfUse) { 296 this.modeOfUse = modeOfUse; 297 } 298 299 /** 300 * Version number to optionally indicate that the contents of the key block 301 * is a component (key part), or to prevent re-injection of an old key. 302 * 303 * @return The key version that corresponds to bytes 9-10 of the key block. 304 */ 305 public String getKeyVersion() { 306 return keyVersion; 307 } 308 309 public void setKeyVersion(String keyVersion) { 310 this.keyVersion = keyVersion; 311 } 312 313 /** 314 * The conditions under which the key can be exported outside the 315 * cryptographic domain. 316 * 317 * @return The key exportability that corresponds to byte 11 of the key block. 318 */ 319 public Exportability getExportability() { 320 return exportability; 321 } 322 323 public void setExportability(Exportability exportability) { 324 this.exportability = exportability; 325 } 326 327 /** 328 * This element is not specified by TR-31 (should contain two ASCII zeros). 329 * <p> 330 * In proprietary derivatives can be used as e.g: LMK identifier. 331 * 332 * @return The reserved that corresponds to bytes 14-15 of the key block. 333 */ 334 public String getReserved() { 335 return reserved; 336 } 337 338 public void setReserved(String reserved) { 339 this.reserved = reserved; 340 } 341 342 /** 343 * The key blok Optional Header Blocks. 344 * <p> 345 * The number of optional heders corresponds to bytes 12-13 of the key block. 346 * <p> 347 * The order of the elements in the map is preserved by {@code LinkedHashMap} 348 * 349 * @return map of Optional Key Blok Heders. 350 */ 351 public Map<String, String> getOptionalHeaders() { 352 return optionalHeaders; 353 } 354 355 /** 356 * The key block MAC ensures the integrity of the key block. 357 * <p> 358 * It is calculated over the Header, Optional Header Blocks and the 359 * encrypted Key Data. 360 * The length of the MAC depends on the type of LMK key: 361 * <ul> 362 * <li>4 bytes for DES Key Block LMK 363 * <li>8 bytes for AES Key Block LMK 364 * </ul> 365 * 366 * @return calculated key block MAC value. 367 */ 368 public byte[] getKeyBlockMAC() { 369 return keyBlockMAC; 370 } 371 372 public void setKeyBlockMAC(byte[] keyBlockMAC) { 373 this.keyBlockMAC = keyBlockMAC; 374 } 375 376 /** 377 * Sets the secure key bytes. 378 * 379 * @param keyBytes bytes representing the secured key 380 */ 381 public void setKeyBytes(byte[] keyBytes) { 382 this.keyBytes = keyBytes; 383 } 384 385 /** 386 * @return The bytes representing the secured key 387 */ 388 public byte[] getKeyBytes() { 389 return keyBytes; 390 } 391 392 /** 393 * The Key Check Value is typically a 24-bits (3 bytes) formed by encrypting a 394 * block of zeros under the secure key when the secure key is clear. 395 * <p> 396 * This check value allows identifying if two secure keys map to the 397 * same clear key. 398 * 399 * @param keyCheckValue the Key Check Value 400 */ 401 public void setKeyCheckValue(byte[] keyCheckValue) { 402 this.keyCheckValue = keyCheckValue; 403 } 404 405 /** 406 * The Key Check Value is typically a 24-bits (3 bytes) formed by encrypting 407 * a block of zeros under the secure key when the secure key is clear. 408 * 409 * @return the Key Check Value 410 */ 411 public byte[] getKeyCheckValue() { 412 return keyCheckValue; 413 } 414 415 /** 416 * Gets optional key name. 417 * 418 * @return name of the key 419 */ 420 public String getKeyName() { 421 return this.keyName; 422 } 423 424 /** 425 * Sets optional key name. 426 * 427 * @param keyName name of the key 428 */ 429 public void setKeyName(String keyName) { 430 this.keyName = keyName; 431 } 432 433 /** 434 * Dumps SecureKeySpec information. 435 * 436 * @param p a print stream usually supplied by Logger 437 * @param indent indention string, usually suppiled by Logger 438 * @see org.jpos.util.Loggeable 439 */ 440 @Override 441 public void dump(PrintStream p, String indent) { 442 String inner = indent + " "; 443 p.print(indent + "<secure-key-spec"); 444 445 if (scheme != null) 446 p.print(" scheme=\"" + scheme + "\""); 447 448 if (keyName != null) 449 p.print(" name=\"" + keyName + "\""); 450 451 p.println(">"); 452 453 if (getKeyLength() > 0) 454 p.println(inner + "<length>" + getKeyLength() + "</length>"); 455 456 if (getKeyType() != null) { 457 p.println(inner + "<type>" + getKeyType() + "</type>"); 458 p.println(inner + "<variant>" + getVariant() + "</variant>"); 459 } 460 461 String keyblok = formKeyHeader(inner); 462 if (keyblok != null) { 463 p.println(inner + "<header>"); 464 p.print(keyblok); 465 p.println(inner + "</header>"); 466 } 467 468 if (!optionalHeaders.isEmpty()) { 469 p.println(inner + "<optional-header>"); 470 String inner2 = inner + " "; 471 for (Entry<String, String> ent : optionalHeaders.entrySet()) 472 p.println(inner2 + "<entry id=\""+ ent.getKey() + "\" value=\""+ ent.getValue()+ "\"/>"); 473 p.println(inner + "</optional-header>"); 474 } 475 476 if (getKeyBytes() != null) 477 p.println(inner + "<data>" + ISOUtil.hexString(getKeyBytes()) + "</data>"); 478 479 if (getKeyBlockMAC() != null) 480 p.println(inner + "<mac>" + ISOUtil.hexString(getKeyBlockMAC()) + "</mac>"); 481 482 if (getKeyCheckValue() != null) 483 p.println(inner + "<check-value>" + ISOUtil.hexString(getKeyCheckValue()) + "</check-value>"); 484 485 p.println(indent + "</secure-key-spec>"); 486 } 487 488 protected String formKeyHeader(String indent) { 489 String inner = indent + " "; 490 try ( 491 ByteArrayOutputStream os = new ByteArrayOutputStream(); 492 PrintStream p = new PrintStream(os); 493 ) { 494 if (keyBlockVersion != 0) 495 p.println(inner + "<version>" + keyBlockVersion + "</version>"); 496 497 if (keyUsage != null) 498 p.println(inner + "<key-usage>" + keyUsage.getCode() + "</key-usage>"); 499 500 if (algorithm != null) 501 p.println(inner + "<algorithm>" + algorithm.getCode() + "</algorithm>"); 502 503 if (modeOfUse != null) 504 p.println(inner + "<mode-of-use>" + modeOfUse.getCode() + "</mode-of-use>"); 505 506 if (keyVersion != null) 507 p.println(inner + "<key-version>" + keyVersion + "</key-version>"); 508 509 if (exportability != null) 510 p.println(inner + "<exportability>" + exportability.getCode() + "</exportability>"); 511 512 if (reserved != null) 513 p.println(inner + "<reserved>" + reserved + "</reserved>"); 514 515 String ret = os.toString(); 516 if (ret.isEmpty()) 517 return null; 518 519 return ret; 520 } catch (IOException ex) { 521 // for close(), it should never happens 522 return null; 523 } 524 } 525 526} 527