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}