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 /** Default constructor. */ 148 public SecureKeySpec() { 149 super(); 150 } 151 152 /** 153 * Key scheme indicates protection metchod appiled to this key by 154 * the security module. 155 * 156 * @param scheme key scheme used to protect this key. 157 */ 158 public void setScheme(KeyScheme scheme) { 159 this.scheme = scheme; 160 } 161 162 /** 163 * Gets the key scheme used to protect this key. 164 * 165 * @return key scheme used to protect this key. 166 */ 167 public KeyScheme getScheme() { 168 return scheme; 169 } 170 171 /** 172 * Sets the length of the key. 173 * <p> 174 * The key length is expressed in bits and refers to clear key <i>(before 175 * LMK protection)</i> 176 * This might be different than the bit length of the secureKeyBytes. 177 * 178 * @param keyLength clear key length in bits 179 */ 180 public void setKeyLength(int keyLength) { 181 this.keyLength = keyLength; 182 } 183 184 /** 185 * Gets the length of the key. 186 * <p> 187 * The key length is expressed in bits and refers to clear key <i>(before 188 * LMK protection)</i> 189 * 190 * @return The length of the clear key 191 */ 192 public int getKeyLength() { 193 return keyLength; 194 } 195 196 /** 197 * Key Type is useful for stating what this key can be used for. 198 * <p> 199 * The value of Key Type specifies whether this secure key is a 200 * <ul> 201 * <li>{@link SMAdapter#TYPE_TMK} Terminal Master Key 202 * <li>{@link SMAdapter#TYPE_ZPK} Zone PIN Key 203 * <li>or others 204 * </ul> 205 * 206 * @param keyType type of the key 207 */ 208 public void setKeyType(String keyType) { 209 this.keyType = keyType; 210 } 211 212 /** 213 * Key Type is useful for stating what this key can be used for. 214 * <p> 215 * The value of Key Type specifies whether this secure key is a 216 * <ul> 217 * <li>{@link SMAdapter#TYPE_TMK} Terminal Master Key 218 * <li>{@link SMAdapter#TYPE_ZPK} Zone PIN Key 219 * <li>or others 220 * </ul> 221 * 222 * @return keyType type of the key 223 */ 224 public String getKeyType() { 225 return this.keyType; 226 } 227 228 /** 229 * Sets key protection variant metchod appiled to this key by the security module. 230 * 231 * @param variant key variant method used to protect this key. 232 */ 233 public void setVariant(int variant) { 234 this.variant = variant; 235 } 236 237 /** 238 * Gets the key variant method used to protect this key. 239 * 240 * @return key variant method used to protect this key. 241 */ 242 public int getVariant() { 243 return this.variant; 244 } 245 246 /** 247 * Identifies the method by which the key block is cryptographically 248 * protected and the content layout of the block. 249 * 250 * @return The key block version that corresponds to byte 0 of the key block. 251 */ 252 public char getKeyBlockVersion() { 253 return keyBlockVersion; 254 } 255 256 /** 257 * Sets the key-block version character (byte 0 of the key block). 258 * 259 * @param keyBlockVersion the version character 260 */ 261 public void setKeyBlockVersion(char keyBlockVersion) { 262 this.keyBlockVersion = keyBlockVersion; 263 } 264 265 /** 266 * The primary usage of the key contained in the key block. 267 * 268 * @return The key usage that corresponds to bytes 5-6 of the key block. 269 */ 270 public KeyUsage getKeyUsage() { 271 return keyUsage; 272 } 273 274 /** 275 * Sets the primary key usage (bytes 5-6 of the key block). 276 * 277 * @param keyUsage the new key usage 278 */ 279 public void setKeyUsage(KeyUsage keyUsage) { 280 this.keyUsage = keyUsage; 281 } 282 283 /** 284 * The cryptographic algorithm with which the key contained in key block 285 * will be used. 286 * 287 * @return The key algorithm that corresponds to byte 7 of the key block. 288 */ 289 public Algorithm getAlgorithm() { 290 return algorithm; 291 } 292 293 /** 294 * Sets the cryptographic algorithm (byte 7 of the key block). 295 * 296 * @param algorithm the new algorithm 297 */ 298 public void setAlgorithm(Algorithm algorithm) { 299 this.algorithm = algorithm; 300 } 301 302 /** 303 * The operation that the key contained in the key block can perform. 304 * 305 * @return The mode of use that corresponds to byte 8 of the key block. 306 */ 307 public ModeOfUse getModeOfUse() { 308 return modeOfUse; 309 } 310 311 /** 312 * Sets the mode of use (byte 8 of the key block). 313 * 314 * @param modeOfUse the new mode of use 315 */ 316 public void setModeOfUse(ModeOfUse modeOfUse) { 317 this.modeOfUse = modeOfUse; 318 } 319 320 /** 321 * Version number to optionally indicate that the contents of the key block 322 * is a component (key part), or to prevent re-injection of an old key. 323 * 324 * @return The key version that corresponds to bytes 9-10 of the key block. 325 */ 326 public String getKeyVersion() { 327 return keyVersion; 328 } 329 330 /** 331 * Sets the key version (bytes 9-10 of the key block). 332 * 333 * @param keyVersion the new key version 334 */ 335 public void setKeyVersion(String keyVersion) { 336 this.keyVersion = keyVersion; 337 } 338 339 /** 340 * The conditions under which the key can be exported outside the 341 * cryptographic domain. 342 * 343 * @return The key exportability that corresponds to byte 11 of the key block. 344 */ 345 public Exportability getExportability() { 346 return exportability; 347 } 348 349 /** 350 * Sets the exportability (byte 11 of the key block). 351 * 352 * @param exportability the new exportability flag 353 */ 354 public void setExportability(Exportability exportability) { 355 this.exportability = exportability; 356 } 357 358 /** 359 * This element is not specified by TR-31 (should contain two ASCII zeros). 360 * <p> 361 * In proprietary derivatives can be used as e.g: LMK identifier. 362 * 363 * @return The reserved that corresponds to bytes 14-15 of the key block. 364 */ 365 public String getReserved() { 366 return reserved; 367 } 368 369 /** 370 * Sets the reserved field (bytes 14-15 of the key block). 371 * 372 * @param reserved the new reserved value 373 */ 374 public void setReserved(String reserved) { 375 this.reserved = reserved; 376 } 377 378 /** 379 * The key blok Optional Header Blocks. 380 * <p> 381 * The number of optional heders corresponds to bytes 12-13 of the key block. 382 * <p> 383 * The order of the elements in the map is preserved by {@code LinkedHashMap} 384 * 385 * @return map of Optional Key Blok Heders. 386 */ 387 public Map<String, String> getOptionalHeaders() { 388 return optionalHeaders; 389 } 390 391 /** 392 * The key block MAC ensures the integrity of the key block. 393 * <p> 394 * It is calculated over the Header, Optional Header Blocks and the 395 * encrypted Key Data. 396 * The length of the MAC depends on the type of LMK key: 397 * <ul> 398 * <li>4 bytes for DES Key Block LMK 399 * <li>8 bytes for AES Key Block LMK 400 * </ul> 401 * 402 * @return calculated key block MAC value. 403 */ 404 public byte[] getKeyBlockMAC() { 405 return keyBlockMAC; 406 } 407 408 /** 409 * Sets the key block MAC. 410 * 411 * @param keyBlockMAC the MAC bytes 412 */ 413 public void setKeyBlockMAC(byte[] keyBlockMAC) { 414 this.keyBlockMAC = keyBlockMAC; 415 } 416 417 /** 418 * Sets the secure key bytes. 419 * 420 * @param keyBytes bytes representing the secured key 421 */ 422 public void setKeyBytes(byte[] keyBytes) { 423 this.keyBytes = keyBytes; 424 } 425 426 /** 427 * Returns the secure (LMK-protected) key bytes. 428 * 429 * @return The bytes representing the secured key 430 */ 431 public byte[] getKeyBytes() { 432 return keyBytes; 433 } 434 435 /** 436 * The Key Check Value is typically a 24-bits (3 bytes) formed by encrypting a 437 * block of zeros under the secure key when the secure key is clear. 438 * <p> 439 * This check value allows identifying if two secure keys map to the 440 * same clear key. 441 * 442 * @param keyCheckValue the Key Check Value 443 */ 444 public void setKeyCheckValue(byte[] keyCheckValue) { 445 this.keyCheckValue = keyCheckValue; 446 } 447 448 /** 449 * The Key Check Value is typically a 24-bits (3 bytes) formed by encrypting 450 * a block of zeros under the secure key when the secure key is clear. 451 * 452 * @return the Key Check Value 453 */ 454 public byte[] getKeyCheckValue() { 455 return keyCheckValue; 456 } 457 458 /** 459 * Gets optional key name. 460 * 461 * @return name of the key 462 */ 463 public String getKeyName() { 464 return this.keyName; 465 } 466 467 /** 468 * Sets optional key name. 469 * 470 * @param keyName name of the key 471 */ 472 public void setKeyName(String keyName) { 473 this.keyName = keyName; 474 } 475 476 /** 477 * Dumps SecureKeySpec information. 478 * 479 * @param p a print stream usually supplied by Logger 480 * @param indent indention string, usually suppiled by Logger 481 * @see org.jpos.util.Loggeable 482 */ 483 @Override 484 public void dump(PrintStream p, String indent) { 485 String inner = indent + " "; 486 p.print(indent + "<secure-key-spec"); 487 488 if (scheme != null) 489 p.print(" scheme=\"" + scheme + "\""); 490 491 if (keyName != null) 492 p.print(" name=\"" + keyName + "\""); 493 494 p.println(">"); 495 496 if (getKeyLength() > 0) 497 p.println(inner + "<length>" + getKeyLength() + "</length>"); 498 499 if (getKeyType() != null) { 500 p.println(inner + "<type>" + getKeyType() + "</type>"); 501 p.println(inner + "<variant>" + getVariant() + "</variant>"); 502 } 503 504 String keyblok = formKeyHeader(inner); 505 if (keyblok != null) { 506 p.println(inner + "<header>"); 507 p.print(keyblok); 508 p.println(inner + "</header>"); 509 } 510 511 if (!optionalHeaders.isEmpty()) { 512 p.println(inner + "<optional-header>"); 513 String inner2 = inner + " "; 514 for (Entry<String, String> ent : optionalHeaders.entrySet()) 515 p.println(inner2 + "<entry id=\""+ ent.getKey() + "\" value=\""+ ent.getValue()+ "\"/>"); 516 p.println(inner + "</optional-header>"); 517 } 518 519 if (getKeyBytes() != null) 520 p.println(inner + "<data>" + ISOUtil.hexString(getKeyBytes()) + "</data>"); 521 522 if (getKeyBlockMAC() != null) 523 p.println(inner + "<mac>" + ISOUtil.hexString(getKeyBlockMAC()) + "</mac>"); 524 525 if (getKeyCheckValue() != null) 526 p.println(inner + "<check-value>" + ISOUtil.hexString(getKeyCheckValue()) + "</check-value>"); 527 528 p.println(indent + "</secure-key-spec>"); 529 } 530 531 /** 532 * Renders the key-block header fields (version/usage/algorithm/etc.) as XML, indented for {@link #dump}. 533 * 534 * @param indent indent prefix to apply to every emitted line 535 * @return the rendered header XML, or {@code null} if no header fields are set 536 */ 537 protected String formKeyHeader(String indent) { 538 String inner = indent + " "; 539 try ( 540 ByteArrayOutputStream os = new ByteArrayOutputStream(); 541 PrintStream p = new PrintStream(os); 542 ) { 543 if (keyBlockVersion != 0) 544 p.println(inner + "<version>" + keyBlockVersion + "</version>"); 545 546 if (keyUsage != null) 547 p.println(inner + "<key-usage>" + keyUsage.getCode() + "</key-usage>"); 548 549 if (algorithm != null) 550 p.println(inner + "<algorithm>" + algorithm.getCode() + "</algorithm>"); 551 552 if (modeOfUse != null) 553 p.println(inner + "<mode-of-use>" + modeOfUse.getCode() + "</mode-of-use>"); 554 555 if (keyVersion != null) 556 p.println(inner + "<key-version>" + keyVersion + "</key-version>"); 557 558 if (exportability != null) 559 p.println(inner + "<exportability>" + exportability.getCode() + "</exportability>"); 560 561 if (reserved != null) 562 p.println(inner + "<reserved>" + reserved + "</reserved>"); 563 564 String ret = os.toString(); 565 if (ret.isEmpty()) 566 return null; 567 568 return ret; 569 } catch (IOException ex) { 570 // for close(), it should never happens 571 return null; 572 } 573 } 574 575} 576