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 org.jpos.iso.ISOUtil;
022
023import java.io.PrintStream;
024import java.util.regex.Matcher;
025import java.util.regex.Pattern;
026
027/**
028 * The SecureDESKey class represents: <br>
029 * Single, double or triple length DES keys that are secured by a security module.
030 * This is typically the DES key encrypted under one of the Local Master Keys of the
031 * security module.
032 * <p>
033 * SecureDESKey has an extra property "Key Check Value". It allows assuring that
034 * two SecureDESKeys owned by two different parties map
035 * to the same clear key. This can be a useful manual check for successful key
036 * exchange.
037 * <p>
038 * NOTE: The security of SecureDESKey is totally dependent on the security of
039 * the used security module.
040 *
041 * @author Hani S. Kirollos
042 * @author Robert Demski
043 * @see SMAdapter
044 */
045public class SecureDESKey extends SecureVariantKey {
046
047    private static final long serialVersionUID = -9145281998779008306L;
048
049    /**
050     * Regular expression pattern representing key type string value.
051     */
052    protected static final Pattern KEY_TYPE_PATTERN = Pattern.compile("([^:;]*)([:;])?([^:;])?([^:;])?");
053
054    /** Default constructor. */
055    public SecureDESKey() {
056        super();
057    }
058
059    /**
060     * Constructs an SecureDESKey
061     * @param keyLength e.g. LENGTH_DES, LENGTH_DES3_2KEY, LENGTH_DES3_3KEY
062     * @param keyType key-type label (e.g. {@code ZPK}, {@code TMK})
063     * @param variant LMK variant byte applied during encryption under the LMK
064     * @param scheme key scheme (encryption form)
065     * @param keyBytes DES Key in the secure proprietary format of your security module
066     * @param keyCheckValue 3-byte (or longer) key check value
067     * @see SMAdapter
068     */
069    public SecureDESKey (short keyLength, String keyType, byte variant, KeyScheme scheme, byte[] keyBytes,
070            byte[] keyCheckValue) {
071        setKeyLength(keyLength);
072        setKeyType(keyType);
073        setVariant(variant);
074        setScheme(scheme);
075        setKeyBytes(keyBytes);
076        setKeyCheckValue(keyCheckValue);
077    }
078
079    /**
080     * Constructs an SecureDESKey
081     * @param keyLength e.g. LENGTH_DES, LENGTH_DES3_2KEY, LENGTH_DES3_3KEY
082     * @param keyType key-type label (e.g. {@code ZPK}, {@code TMK})
083     * @param keyBytes DES Key in the secure proprietary format of your security module
084     * @param keyCheckValue 3-byte (or longer) key check value
085     * @see SMAdapter
086     */
087    public SecureDESKey (short keyLength, String keyType, byte[] keyBytes,
088            byte[] keyCheckValue) {
089        setKeyLength(keyLength);
090        setKeyType(keyType);
091        setKeyBytes(keyBytes);
092        setKeyCheckValue(keyCheckValue);
093        getVariant(); //only for set variant with defaults
094        getScheme();  //only set scheme with defaults
095    }
096
097    /**
098     * Constructs an SecureDESKey
099     * @param keyLength e.g. LENGTH_DES, LENGTH_DES3_2KEY, LENGTH_DES3_3KEY
100     * @param keyType key-type label (e.g. {@code ZPK}, {@code TMK})
101     * @param keyHexString secure key represented as HexString instead of byte[]
102     * @param keyCheckValueHexString key check value represented as HexString instead of byte[]
103     */
104    public SecureDESKey (short keyLength, String keyType, String keyHexString,
105            String keyCheckValueHexString) {
106        this(keyLength, keyType, ISOUtil.hex2byte(keyHexString), ISOUtil.hex2byte(keyCheckValueHexString));
107    }
108
109    /**
110     * Constructs an SecureDESKey
111     * @param keyLength e.g. LENGTH_DES, LENGTH_DES3_2KEY, LENGTH_DES3_3KEY
112     * @param keyType key-type label (e.g. {@code ZPK}, {@code TMK})
113     * @param variant LMK variant byte applied during encryption under the LMK
114     * @param scheme key scheme (encryption form)
115     * @param keyHexString secure key represented as HexString instead of byte[]
116     * @param keyCheckValueHexString key check value represented as HexString instead of byte[]
117     */
118    public SecureDESKey (short keyLength, String keyType, byte variant, KeyScheme scheme, String keyHexString,
119            String keyCheckValueHexString) {
120        this(keyLength, keyType, variant, scheme, ISOUtil.hex2byte(keyHexString), ISOUtil.hex2byte(keyCheckValueHexString));
121    }
122
123    @Override
124    public byte getVariant () {
125        if (variant!=null)
126            return variant;
127        /**
128         * Some variant derivation if it hasn't been explicity stated
129         */
130        variant = 0;
131        Matcher m = KEY_TYPE_PATTERN.matcher(keyType);
132        m.find();
133        if (m.group(3) != null)
134            try {
135                variant = Byte.valueOf(m.group(3));
136            } catch (NumberFormatException ex){
137                throw new NumberFormatException("Value "+m.group(4)+" is not valid key variant");
138            }
139        return variant;
140    }
141
142    @Override
143    public KeyScheme getScheme () {
144        if (scheme!=null)
145            return scheme;
146        /**
147         * Some scheme derivation if it hasn't been explicity stated
148         */
149        switch (keyLength){
150            case SMAdapter.LENGTH_DES:
151                scheme = KeyScheme.Z; break;
152            case SMAdapter.LENGTH_DES3_2KEY:
153                scheme = KeyScheme.X; break;
154            case SMAdapter.LENGTH_DES3_3KEY:
155                scheme = KeyScheme.Y; break;
156        }
157        Matcher m = KEY_TYPE_PATTERN.matcher(keyType);
158        m.find();
159        if (m.group(4) != null)
160            try {
161                scheme = KeyScheme.valueOf(m.group(4));
162            } catch (IllegalArgumentException ex){
163                throw new IllegalArgumentException("Value "+m.group(4)+" is not valid key scheme");
164            }
165        return scheme;
166    }
167
168    /**
169     * dumps SecureDESKey basic information
170     * @param p a PrintStream usually supplied by Logger
171     * @param indent indention string, usually suppiled by Logger
172     * @see org.jpos.util.Loggeable
173     */
174    @Override
175    public void dump (PrintStream p, String indent) {
176        String inner = indent + "  ";
177        p.print(indent + "<secure-des-key");
178        p.print(" length=\"" + getKeyLength() + "\"");
179        p.print(" type=\"" + keyType + "\"");
180        p.print(" variant=\"" + getVariant() + "\"");
181        p.print(" scheme=\"" + this.getScheme() + "\"");
182        if (keyName != null)
183            p.print(" name=\"" + keyName + "\"");
184
185        p.println(">");
186        p.println(inner + "<data>" + ISOUtil.hexString(getKeyBytes()) + "</data>");
187        p.println(inner + "<check-value>" + ISOUtil.hexString(getKeyCheckValue()) + "</check-value>");
188        p.println(indent + "</secure-des-key>");
189    }
190}
191
192
193