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