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.javatuples.Pair;
022import org.jpos.core.Configurable;
023import org.jpos.core.Configuration;
024import org.jpos.core.ConfigurationException;
025import org.jpos.iso.ISOUtil;
026import org.jpos.util.LogEvent;
027import org.jpos.util.LogSource;
028import org.jpos.util.Loggeable;
029import org.jpos.util.Logger;
030import org.jpos.util.NameRegistrar;
031import org.jpos.util.NameRegistrar.NotFoundException;
032import org.jpos.util.SimpleMsg;
033
034import java.security.MessageDigest;
035import java.security.PublicKey;
036import java.security.spec.AlgorithmParameterSpec;
037import java.util.ArrayList;
038import java.util.Date;
039import java.util.List;
040import java.util.Map;
041
042/**
043 * <p>
044 * Provides base functionality for the actual Security Module Adapter.
045 * </p>
046 * <p>
047 * You adapter needs to override the methods that end with "Impl"
048 * </p>
049 * @author Hani S. Kirollos
050 * @version $Revision$ $Date$
051 */
052public class BaseSMAdapter<T>
053        implements SMAdapter<T>, Configurable, LogSource {
054    protected Logger logger = null;
055    protected String realm = null;
056    protected Configuration cfg;
057    private String name;
058    private boolean debug;
059
060    public BaseSMAdapter () {
061        super();
062    }
063
064    public BaseSMAdapter (Configuration cfg, Logger logger, String realm) throws ConfigurationException
065    {
066        super();
067        setLogger(logger, realm);
068        setConfiguration(cfg);
069    }
070
071    @Override
072    public void setConfiguration (Configuration cfg) throws ConfigurationException {
073        this.cfg = cfg;
074        debug = cfg.getBoolean("debug", false);
075    }
076
077    @Override
078    public void setLogger (Logger logger, String realm) {
079        this.logger = logger;
080        this.realm = realm;
081    }
082
083    @Override
084    public Logger getLogger () {
085        return  logger;
086    }
087
088    @Override
089    public String getRealm () {
090        return  realm;
091    }
092
093    /**
094     * associates this SMAdapter with a name using NameRegistrar
095     * @param name name to register
096     * @see NameRegistrar
097     */
098    public void setName (String name) {
099        this.name = name;
100        NameRegistrar.register("s-m-adapter." + name, this);
101    }
102
103    /**
104     * @return this SMAdapter's name ("" if no name was set)
105     */
106    public String getName () {
107        return  this.name;
108    }
109
110    /**
111     * @param name
112     * @return SMAdapter instance with given name.
113     * @throws NotFoundException
114     * @see NameRegistrar
115     */
116    public static SMAdapter getSMAdapter (String name) throws NameRegistrar.NotFoundException {
117        return  (SMAdapter)NameRegistrar.get("s-m-adapter." + name);
118    }
119
120    @Override
121    public SecureDESKey generateKey (short keyLength, String keyType) throws SMException {
122        List<Loggeable> cmdParameters = new ArrayList<>();
123        cmdParameters.add(new SimpleMsg("parameter", "Key Length", keyLength));
124        cmdParameters.add(new SimpleMsg("parameter", "Key Type", keyType));
125        LogEvent evt = new LogEvent(this, "s-m-operation");
126        evt.addMessage(new SimpleMsg("command", "Generate Key", cmdParameters));
127        SecureDESKey result = null;
128        try {
129            result = generateKeyImpl(keyLength, keyType);
130            evt.addMessage(new SimpleMsg("result", "Generated Key", result));
131        } catch (Exception e) {
132            evt.addMessage(e);
133            throw  e instanceof SMException ? (SMException) e : new SMException(e);
134        } finally {
135            logEvent(evt);
136        }
137        return  result;
138    }
139
140    @Override
141    public SecureKey generateKey(SecureKeySpec keySpec) throws SMException {
142        List<Loggeable> cmdParameters = new ArrayList<>();
143        cmdParameters.add(new SimpleMsg("parameter", "Key Specification", keySpec));
144        LogEvent evt = new LogEvent(this, "s-m-operation");
145        evt.addMessage(new SimpleMsg("command", "Generate Key", cmdParameters));
146        SecureKey result = null;
147        try {
148            result = generateKeyImpl(keySpec);
149            evt.addMessage(new SimpleMsg("result", "Generated Key", result));
150        } catch (Exception e) {
151            evt.addMessage(e);
152            throw e instanceof SMException ? (SMException) e : new SMException(e);
153        } finally {
154            logEvent(evt);
155        }
156        return  result;
157    }
158
159    @Override
160    public byte[] generateKeyCheckValue(T kd) throws SMException {
161        List<Loggeable> cmdParameters = new ArrayList<>();
162        cmdParameters.add(new SimpleMsg("parameter", "Key with untrusted check value", kd));
163        LogEvent evt = new LogEvent(this, "s-m-operation");
164        evt.addMessage(new SimpleMsg("command", "Generate Key Check Value", cmdParameters));
165        byte[] result = null;
166        try {
167            result = generateKeyCheckValueImpl(kd);
168            evt.addMessage(new SimpleMsg("result", "Generated Key Check Value", ISOUtil.hexString(result)));
169        } catch (Exception e) {
170            evt.addMessage(e);
171            throw  e instanceof SMException ? (SMException) e : new SMException(e);
172        } finally {
173            logEvent(evt);
174        }
175        return  result;
176    }
177
178    @Override
179    public SecureDESKey translateKeyScheme(SecureDESKey key, KeyScheme destKeyScheme)
180            throws SMException {
181        List<Loggeable> cmdParameters = new ArrayList<>();
182        cmdParameters.add(new SimpleMsg("parameter", "Key", key));
183        cmdParameters.add(new SimpleMsg("parameter", "Destination Key Scheme", destKeyScheme));
184        LogEvent evt = new LogEvent(this, "s-m-operation");
185        evt.addMessage(new SimpleMsg("command", "Translate Key Scheme", cmdParameters));
186        SecureDESKey result = null;
187        try {
188            result = translateKeySchemeImpl(key, destKeyScheme);
189            evt.addMessage(new SimpleMsg("result", "Translate Key Scheme", result));
190        } catch (Exception e) {
191            evt.addMessage(e);
192            throw  e instanceof SMException ? (SMException) e : new SMException(e);
193        } finally {
194            logEvent(evt);
195        }
196        return  result;
197    }
198
199    @Override
200    public SecureDESKey importKey (short keyLength, String keyType, byte[] encryptedKey,
201            SecureDESKey kek, boolean checkParity) throws SMException {
202        List<Loggeable> cmdParameters = new ArrayList<>();
203        cmdParameters.add(new SimpleMsg("parameter", "Key Length", keyLength));
204        cmdParameters.add(new SimpleMsg("parameter", "Key Type", keyType));
205        cmdParameters.add(new SimpleMsg("parameter", "Encrypted Key", encryptedKey));
206        cmdParameters.add(new SimpleMsg("parameter", "Key-Encrypting Key", kek));
207        cmdParameters.add(new SimpleMsg("parameter", "Check Parity", checkParity));
208        LogEvent evt = new LogEvent(this, "s-m-operation");
209        evt.addMessage(new SimpleMsg("command", "Import Key", cmdParameters));
210        SecureDESKey result = null;
211        try {
212            result = importKeyImpl(keyLength, keyType, encryptedKey, kek, checkParity);
213            evt.addMessage(new SimpleMsg("result", "Imported Key", result));
214        } catch (Exception e) {
215            evt.addMessage(e);
216            throw  e instanceof SMException ? (SMException) e : new SMException(e);
217        } finally {
218            logEvent(evt);
219        }
220        return  result;
221    }
222
223    @Override
224    public SecureKey importKey(SecureKey kek, SecureKey key, SecureKeySpec keySpec
225            , boolean checkParity) throws SMException {
226        List<Loggeable> cmdParameters = new ArrayList<>();
227        cmdParameters.add(new SimpleMsg("parameter", "Key-Encrypting Key", kek));
228        cmdParameters.add(new SimpleMsg("parameter", "Encrypted Key", key));
229        cmdParameters.add(new SimpleMsg("parameter", "Key Specification", keySpec));
230        cmdParameters.add(new SimpleMsg("parameter", "Check Parity", checkParity));
231        LogEvent evt = new LogEvent(this, "s-m-operation");
232        evt.addMessage(new SimpleMsg("command", "Import Key", cmdParameters));
233        SecureKey result = null;
234        try {
235            result = importKeyImpl(kek, key, keySpec, checkParity);
236            evt.addMessage(new SimpleMsg("result", "Imported Key", result));
237        } catch (Exception e) {
238            evt.addMessage(e);
239            throw  e instanceof SMException ? (SMException) e : new SMException(e);
240        } finally {
241            logEvent(evt);
242        }
243        return  result;
244    }
245
246    @Override
247    public byte[] exportKey (SecureDESKey key, SecureDESKey kek) throws SMException {
248        List<Loggeable> cmdParameters = new ArrayList<>();
249        cmdParameters.add(new SimpleMsg("parameter", "Key", key));
250        cmdParameters.add(new SimpleMsg("parameter", "Key-Encrypting Key", kek));
251        LogEvent evt = new LogEvent(this, "s-m-operation");
252        evt.addMessage(new SimpleMsg("command", "Export Key", cmdParameters));
253        byte[] result = null;
254        try {
255            result = exportKeyImpl(key, kek);
256            evt.addMessage(new SimpleMsg("result", "Exported Key", result));
257        } catch (Exception e) {
258            evt.addMessage(e);
259            throw  e instanceof SMException ? (SMException) e : new SMException(e);
260        } finally {
261            logEvent(evt);
262        }
263        return  result;
264    }
265
266    @Override
267    public SecureKey exportKey(SecureKey kek, SecureKey key, SecureKeySpec keySpec)
268            throws SMException {
269        List<Loggeable> cmdParameters = new ArrayList<>();
270        cmdParameters.add(new SimpleMsg("parameter", "Key-Encrypting Key", kek));
271        cmdParameters.add(new SimpleMsg("parameter", "Key", key));
272        cmdParameters.add(new SimpleMsg("parameter", "Key Specification", keySpec));
273        LogEvent evt = new LogEvent(this, "s-m-operation");
274        evt.addMessage(new SimpleMsg("command", "Export Key", cmdParameters));
275        SecureKey result = null;
276        try {
277            result = exportKeyImpl(kek, key, keySpec);
278            evt.addMessage(new SimpleMsg("result", "Exported Key", result));
279        } catch (Exception e) {
280            evt.addMessage(e);
281            throw  e instanceof SMException ? (SMException) e : new SMException(e);
282        } finally {
283            logEvent(evt);
284        }
285        return  result;
286    }
287
288    @Override
289    public EncryptedPIN encryptPIN (String pin, String accountNumber, boolean extract) throws SMException {
290        accountNumber = extract ? EncryptedPIN.extractAccountNumberPart(accountNumber) : accountNumber;
291        List<Loggeable> cmdParameters = new ArrayList<>();
292        cmdParameters.add(new SimpleMsg("parameter", "clear pin", pin));
293        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNumber));
294        LogEvent evt = new LogEvent(this, "s-m-operation");
295        evt.addMessage(new SimpleMsg("command", "Encrypt Clear PIN", cmdParameters));
296        EncryptedPIN result = null;
297        try {
298            result = encryptPINImpl(pin, accountNumber);
299            evt.addMessage(new SimpleMsg("result", "PIN under LMK", result));
300        } catch (Exception e) {
301            evt.addMessage(e);
302            throw  e instanceof SMException ? (SMException) e : new SMException(e);
303        } finally {
304            logEvent(evt);
305        }
306        return  result;
307    }
308    @Override
309    public EncryptedPIN encryptPIN (String pin, String accountNumber) throws SMException {
310        return encryptPIN(pin, accountNumber, true);
311    }
312
313    @Override
314    public EncryptedPIN encryptPIN(String pin, String accountNumber, T pek) throws SMException {
315        accountNumber = EncryptedPIN.extractAccountNumberPart(accountNumber);
316        List<Loggeable> cmdParameters = new ArrayList<>();
317        cmdParameters.add(new SimpleMsg("parameter", "clear pin", pin));
318        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNumber));
319        cmdParameters.add(new SimpleMsg("parameter", "pin encryption Key", pek));
320        LogEvent evt = new LogEvent(this, "s-m-operation");
321        evt.addMessage(new SimpleMsg("command", "Encrypt clear PIN under PEK", cmdParameters));
322        EncryptedPIN result = null;
323        try {
324            result = encryptPINImpl(pin, accountNumber, pek);
325            evt.addMessage(new SimpleMsg("result", "PIN under PEK", result));
326        } 
327        catch (Exception e) {
328            evt.addMessage(e);
329            throw e instanceof SMException ? (SMException) e : new SMException(e);
330        } 
331        finally {
332            logEvent(evt);
333        }
334        return result;
335    }
336
337    @Override
338    public String decryptPIN (EncryptedPIN pinUnderLmk) throws SMException {
339        List<Loggeable> cmdParameters = new ArrayList<>();
340        cmdParameters.add(new SimpleMsg("parameter", "PIN under LMK", pinUnderLmk));
341        LogEvent evt = new LogEvent(this, "s-m-operation");
342        evt.addMessage(new SimpleMsg("command", "Decrypt PIN", cmdParameters));
343        String result = null;
344        try {
345            result = decryptPINImpl(pinUnderLmk);
346            evt.addMessage(new SimpleMsg("result", "clear PIN", result));
347        } catch (Exception e) {
348            evt.addMessage(e);
349            throw  e instanceof SMException ? (SMException) e : new SMException(e);
350        } finally {
351            logEvent(evt);
352        }
353        return  result;
354    }
355
356    @Override
357    public EncryptedPIN importPIN(EncryptedPIN pinUnderKd1, T kd1) throws SMException {
358        List<Loggeable> cmdParameters = new ArrayList<>();
359        cmdParameters.add(new SimpleMsg("parameter", "PIN under Data Key 1", pinUnderKd1));
360        cmdParameters.add(new SimpleMsg("parameter", "Data Key 1", kd1));
361        LogEvent evt = new LogEvent(this, "s-m-operation");
362        evt.addMessage(new SimpleMsg("command", "Import PIN", cmdParameters));
363        EncryptedPIN result = null;
364        try {
365            result = importPINImpl(pinUnderKd1, kd1);
366            evt.addMessage(new SimpleMsg("result", "PIN under LMK", result));
367        } catch (Exception e) {
368            evt.addMessage(e);
369            throw  e instanceof SMException ? (SMException) e : new SMException(e);
370        } finally {
371            logEvent(evt);
372        }
373        return  result;
374    }
375
376    @Override
377    public EncryptedPIN translatePIN(EncryptedPIN pinUnderKd1, T kd1,
378            T kd2, byte destinationPINBlockFormat) throws SMException {
379        List<Loggeable> cmdParameters = new ArrayList<>();
380        cmdParameters.add(new SimpleMsg("parameter", "PIN under Data Key 1", pinUnderKd1));
381        cmdParameters.add(new SimpleMsg("parameter", "Data Key 1", kd1));
382        cmdParameters.add(new SimpleMsg("parameter", "Data Key 2", kd2));
383        cmdParameters.add(new SimpleMsg("parameter", "Destination PIN Block Format", destinationPINBlockFormat));
384        LogEvent evt = new LogEvent(this, "s-m-operation");
385        evt.addMessage(new SimpleMsg("command", "Translate PIN from Data Key 1 to Data Key 2",
386                cmdParameters));
387        EncryptedPIN result = null;
388        try {
389            result = translatePINImpl(pinUnderKd1, kd1, kd2, destinationPINBlockFormat);
390            evt.addMessage(new SimpleMsg("result", "PIN under Data Key 2", result));
391        } catch (Exception e) {
392            evt.addMessage(e);
393            throw  e instanceof SMException ? (SMException) e : new SMException(e);
394        } finally {
395            logEvent(evt);
396        }
397        return  result;
398    }
399
400    @Override
401    public EncryptedPIN importPIN(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
402            T bdk) throws SMException {
403        return importPIN(pinUnderDuk,ksn,bdk,false);
404    }
405
406    @Override
407    public EncryptedPIN importPIN(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
408            T bdk, boolean tdes) throws SMException {
409        List<Loggeable> cmdParameters = new ArrayList<>();
410        cmdParameters.add(new SimpleMsg("parameter", "PIN under Derived Unique Key", pinUnderDuk));
411        cmdParameters.add(new SimpleMsg("parameter", "Key Serial Number", ksn));
412        cmdParameters.add(new SimpleMsg("parameter", "Base Derivation Key", bdk));
413        LogEvent evt = new LogEvent(this, "s-m-operation");
414        evt.addMessage(new SimpleMsg("command", "Import PIN", cmdParameters));
415        EncryptedPIN result = null;
416        try {
417            result = importPINImpl(pinUnderDuk, ksn, bdk, tdes);
418            evt.addMessage(new SimpleMsg("result", "PIN under LMK", result));
419        } catch (Exception e) {
420            evt.addMessage(e);
421            throw  e instanceof SMException ? (SMException) e : new SMException(e);
422        } finally {
423            logEvent(evt);
424        }
425        return  result;
426    }
427
428    @Override
429    public EncryptedPIN translatePIN(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
430            T bdk, T kd2, byte destinationPINBlockFormat) throws SMException {
431        return translatePIN(pinUnderDuk,ksn,bdk,kd2,destinationPINBlockFormat,false);
432    }
433
434    @Override
435    public EncryptedPIN translatePIN(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
436            T bdk, T kd2, byte destinationPINBlockFormat, boolean tdes) throws SMException {
437        List<Loggeable> cmdParameters = new ArrayList<>();
438        cmdParameters.add(new SimpleMsg("parameter", "PIN under Derived Unique Key", pinUnderDuk));
439        cmdParameters.add(new SimpleMsg("parameter", "Key Serial Number", ksn));
440        cmdParameters.add(new SimpleMsg("parameter", "Base Derivation Key", bdk));
441        cmdParameters.add(new SimpleMsg("parameter", "Data Key 2", kd2));
442        cmdParameters.add(new SimpleMsg("parameter", "Destination PIN Block Format", destinationPINBlockFormat));
443        LogEvent evt = new LogEvent(this, "s-m-operation");
444        evt.addMessage(new SimpleMsg("command", "Translate PIN", cmdParameters));
445        EncryptedPIN result = null;
446        try {
447            result = translatePINImpl(pinUnderDuk, ksn, bdk, kd2, destinationPINBlockFormat,tdes);
448            evt.addMessage(new SimpleMsg("result", "PIN under Data Key 2", result));
449        } catch (Exception e) {
450            evt.addMessage(e);
451            throw  e instanceof SMException ? (SMException) e : new SMException(e);
452        } finally {
453            logEvent(evt);
454        }
455        return  result;
456    }
457
458    @Override
459    public EncryptedPIN exportPIN(EncryptedPIN pinUnderLmk, T kd2, byte destinationPINBlockFormat) throws SMException {
460        List<Loggeable> cmdParameters = new ArrayList<>();
461        cmdParameters.add(new SimpleMsg("parameter", "PIN under LMK", pinUnderLmk));
462        cmdParameters.add(new SimpleMsg("parameter", "Data Key 2", kd2));
463        cmdParameters.add(new SimpleMsg("parameter", "Destination PIN Block Format", destinationPINBlockFormat));
464        LogEvent evt = new LogEvent(this, "s-m-operation");
465        evt.addMessage(new SimpleMsg("command", "Export PIN", cmdParameters));
466        EncryptedPIN result = null;
467        try {
468            result = exportPINImpl(pinUnderLmk, kd2, destinationPINBlockFormat);
469            evt.addMessage(new SimpleMsg("result", "PIN under Data Key 2", result));
470        } catch (Exception e) {
471            evt.addMessage(e);
472            throw  e instanceof SMException ? (SMException) e : new SMException(e);
473        } finally {
474            logEvent(evt);
475        }
476        return  result;
477    }
478
479    @Override
480    public EncryptedPIN generatePIN(String accountNumber, int pinLen)
481            throws SMException {
482      return generatePIN(accountNumber, pinLen, null);
483    }
484
485    @Override
486    public EncryptedPIN generatePIN(String accountNumber, int pinLen, List<String> excludes)
487            throws SMException {
488      List<Loggeable> cmdParameters = new ArrayList<>();
489      cmdParameters.add(new SimpleMsg("parameter", "account number", accountNumber));
490      cmdParameters.add(new SimpleMsg("parameter", "PIN length", pinLen));
491      if(excludes != null && !excludes.isEmpty())
492        cmdParameters.add(new SimpleMsg("parameter", "Excluded PINs list", excludes));
493
494      LogEvent evt = new LogEvent(this, "s-m-operation");
495      evt.addMessage(new SimpleMsg("command", "Generate PIN", cmdParameters));
496      EncryptedPIN result = null;
497      try {
498        result = generatePINImpl(accountNumber, pinLen, excludes);
499        evt.addMessage(new SimpleMsg("result", "Generated PIN", result));
500      } catch (Exception e) {
501        evt.addMessage(e);
502        throw e instanceof SMException ? (SMException) e : new SMException(e);
503      } finally {
504        logEvent(evt);
505      }
506      return result;
507    }
508
509    @Override
510    public void printPIN(String accountNo, EncryptedPIN pinUnderKd1, T kd1
511                         ,String template, Map<String, String> fields) throws SMException {
512      List<Loggeable> cmdParameters = new ArrayList<>();
513      cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo == null ? "" : accountNo));
514      cmdParameters.add(new SimpleMsg("parameter", "PIN under Key data 1", pinUnderKd1 == null ? "" : pinUnderKd1));
515      if (kd1!=null)
516        cmdParameters.add(new SimpleMsg("parameter", "Key data 1", kd1));
517      cmdParameters.add(new SimpleMsg("parameter", "Template", template == null ? "" : template));
518      if (fields!=null)
519        cmdParameters.add(new SimpleMsg("parameter", "Fields", fields));
520
521      LogEvent evt = new LogEvent(this, "s-m-operation");
522      evt.addMessage(new SimpleMsg("command", "Print PIN", cmdParameters));
523      try {
524          printPINImpl(accountNo, pinUnderKd1, kd1, template, fields);
525      } catch (Exception e) {
526          evt.addMessage(e);
527          throw  e instanceof SMException ? (SMException) e : new SMException(e);
528      } finally {
529          logEvent(evt);
530      }
531    }
532
533    @Override
534    public String calculatePVV(EncryptedPIN pinUnderLMK, T pvkA,
535                               T pvkB, int pvkIdx) throws SMException {
536      return calculatePVV(pinUnderLMK, pvkA, pvkB, pvkIdx, null);
537    }
538
539    @Override
540    public String calculatePVV(EncryptedPIN pinUnderLMK, T pvkA,
541                               T pvkB, int pvkIdx, List<String> excludes)
542            throws SMException {
543      List<Loggeable> cmdParameters = new ArrayList<>();
544      cmdParameters.add(new SimpleMsg("parameter", "account number", pinUnderLMK.getAccountNumber()));
545      cmdParameters.add(new SimpleMsg("parameter", "PIN under LMK", pinUnderLMK));
546      cmdParameters.add(new SimpleMsg("parameter", "PVK-A", pvkA == null ? "" : pvkA));
547      cmdParameters.add(new SimpleMsg("parameter", "PVK-B", pvkB == null ? "" : pvkB));
548      cmdParameters.add(new SimpleMsg("parameter", "PVK index", pvkIdx));
549      if(excludes != null && !excludes.isEmpty())
550        cmdParameters.add(new SimpleMsg("parameter", "Excluded PINs list", excludes));
551      LogEvent evt = new LogEvent(this, "s-m-operation");
552      evt.addMessage(new SimpleMsg("command", "Calculate PVV", cmdParameters));
553      String result = null;
554      try {
555        result = calculatePVVImpl(pinUnderLMK, pvkA, pvkB, pvkIdx, excludes);
556        evt.addMessage(new SimpleMsg("result", "Calculated PVV", result));
557      } catch (Exception e) {
558        evt.addMessage(e);
559        throw e instanceof SMException ? (SMException) e : new SMException(e);
560      } finally {
561        logEvent(evt);
562      }
563      return result;
564    }
565
566    @Override
567    public String calculatePVV(EncryptedPIN pinUnderKd1, T kd1,
568                               T pvkA, T pvkB, int pvkIdx)
569            throws SMException {
570      return calculatePVV(pinUnderKd1, kd1, pvkA, pvkB, pvkIdx, null);
571    }
572
573    @Override
574    public String calculatePVV(EncryptedPIN pinUnderKd1, T kd1,
575                               T pvkA, T pvkB, int pvkIdx,
576                               List<String> excludes) throws SMException {
577      List<Loggeable> cmdParameters = new ArrayList<>();
578      cmdParameters.add(new SimpleMsg("parameter", "account number", pinUnderKd1.getAccountNumber()));
579      cmdParameters.add(new SimpleMsg("parameter", "PIN under Data Key 1", pinUnderKd1));
580      cmdParameters.add(new SimpleMsg("parameter", "Data Key 1", kd1));
581      cmdParameters.add(new SimpleMsg("parameter", "PVK-A", pvkA == null ? "" : pvkA));
582      cmdParameters.add(new SimpleMsg("parameter", "PVK-B", pvkB == null ? "" : pvkB));
583      cmdParameters.add(new SimpleMsg("parameter", "PVK index", pvkIdx));
584      if(excludes != null && !excludes.isEmpty())
585        cmdParameters.add(new SimpleMsg("parameter", "Excluded PINs list", excludes));
586      LogEvent evt = new LogEvent(this, "s-m-operation");
587      evt.addMessage(new SimpleMsg("command", "Calculate PVV", cmdParameters));
588      String result = null;
589      try {
590        result = calculatePVVImpl(pinUnderKd1, kd1, pvkA, pvkB, pvkIdx, excludes);
591        evt.addMessage(new SimpleMsg("result", "Calculated PVV", result));
592      } catch (Exception e) {
593        evt.addMessage(e);
594        throw e instanceof SMException ? (SMException) e : new SMException(e);
595      } finally {
596        logEvent(evt);
597      }
598      return result;
599    }
600
601    @Override
602    public boolean verifyPVV(EncryptedPIN pinUnderKd1, T kd1, T pvkA,
603                          T pvkB, int pvki, String pvv) throws SMException {
604        List<Loggeable> cmdParameters = new ArrayList<>();
605        cmdParameters.add(new SimpleMsg("parameter", "account number", pinUnderKd1.getAccountNumber()));
606        cmdParameters.add(new SimpleMsg("parameter", "PIN under Data Key 1", pinUnderKd1));
607        cmdParameters.add(new SimpleMsg("parameter", "Data Key 1", kd1));
608        cmdParameters.add(new SimpleMsg("parameter", "PVK-A", pvkA == null ? "" : pvkA));
609        cmdParameters.add(new SimpleMsg("parameter", "PVK-B", pvkB == null ? "" : pvkB));
610        cmdParameters.add(new SimpleMsg("parameter", "pvki", pvki));
611        cmdParameters.add(new SimpleMsg("parameter", "pvv", pvv));
612      LogEvent evt = new LogEvent(this, "s-m-operation");
613      evt.addMessage(new SimpleMsg("command", "Verify a PIN Using the VISA Method", cmdParameters));
614
615      try {
616        boolean r = verifyPVVImpl(pinUnderKd1, kd1, pvkA, pvkB, pvki, pvv);
617        evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
618        return r;
619      } catch (Exception e) {
620        evt.addMessage(e);
621        throw e instanceof SMException ? (SMException) e : new SMException(e);
622      } finally {
623        logEvent(evt);
624      }
625    }
626
627    @Override
628    public String calculateIBMPINOffset(EncryptedPIN pinUnderLmk, T pvk,
629                           String decTab, String pinValData, int minPinLen)
630            throws SMException {
631      return calculateIBMPINOffset(pinUnderLmk, pvk, decTab, pinValData, minPinLen, null);
632    }
633
634    @Override
635    public String calculateIBMPINOffset(EncryptedPIN pinUnderLmk, T pvk,
636                           String decTab, String pinValData, int minPinLen,
637                           List<String> excludes) throws SMException {
638      List<Loggeable> cmdParameters = new ArrayList<>();
639      cmdParameters.add(new SimpleMsg("parameter", "account number", pinUnderLmk.getAccountNumber()));
640      cmdParameters.add(new SimpleMsg("parameter", "PIN under LMK", pinUnderLmk));
641      cmdParameters.add(new SimpleMsg("parameter", "PVK", pvk));
642      cmdParameters.add(new SimpleMsg("parameter", "decimalisation table", decTab));
643      cmdParameters.add(new SimpleMsg("parameter", "PIN validation data", pinValData));
644      cmdParameters.add(new SimpleMsg("parameter", "minimum PIN length", minPinLen));
645      if(excludes != null && !excludes.isEmpty())
646        cmdParameters.add(new SimpleMsg("parameter", "Excluded PINs list", excludes));
647      LogEvent evt = new LogEvent(this, "s-m-operation");
648      evt.addMessage(new SimpleMsg("command", "Calculate PIN offset", cmdParameters));
649      String result = null;
650      try {
651        result = calculateIBMPINOffsetImpl(pinUnderLmk, pvk,
652                decTab, pinValData, minPinLen, excludes);
653        evt.addMessage(new SimpleMsg("result", "Calculated PIN offset", result));
654      } catch (Exception e) {
655        evt.addMessage(e);
656        throw e instanceof SMException ? (SMException) e : new SMException(e);
657      } finally {
658        logEvent(evt);
659      }
660      return result;
661    }
662
663    @Override
664    public String calculateIBMPINOffset(EncryptedPIN pinUnderKd1, T kd1,
665                           T pvk, String decTab, String pinValData, int minPinLen)
666            throws SMException {
667      return calculateIBMPINOffset(pinUnderKd1, kd1, pvk, decTab,
668              pinValData, minPinLen, null);
669    }
670
671    @Override
672    public String calculateIBMPINOffset(EncryptedPIN pinUnderKd1, T kd1,
673                           T pvk, String decTab, String pinValData, int minPinLen,
674                           List<String> excludes) throws SMException {
675      List<Loggeable> cmdParameters = new ArrayList<>();
676      cmdParameters.add(new SimpleMsg("parameter", "account number", pinUnderKd1.getAccountNumber()));
677      cmdParameters.add(new SimpleMsg("parameter", "PIN under Data Key 1", pinUnderKd1));
678      cmdParameters.add(new SimpleMsg("parameter", "Data Key 1", kd1));
679      cmdParameters.add(new SimpleMsg("parameter", "PVK", pvk));
680      cmdParameters.add(new SimpleMsg("parameter", "decimalisation table", decTab));
681      cmdParameters.add(new SimpleMsg("parameter", "PIN validation data", pinValData));
682      cmdParameters.add(new SimpleMsg("parameter", "minimum PIN length", minPinLen));
683      if(excludes != null && !excludes.isEmpty())
684        cmdParameters.add(new SimpleMsg("parameter", "Excluded PINs list", excludes));
685      LogEvent evt = new LogEvent(this, "s-m-operation");
686      evt.addMessage(new SimpleMsg("command", "Calculate PIN offset", cmdParameters));
687      String result = null;
688      try {
689        result = calculateIBMPINOffsetImpl(pinUnderKd1, kd1, pvk,
690                decTab, pinValData, minPinLen, excludes);
691        evt.addMessage(new SimpleMsg("result", "Calculated PIN offset", result));
692      } catch (Exception e) {
693        evt.addMessage(e);
694        throw e instanceof SMException ? (SMException) e : new SMException(e);
695      } finally {
696        logEvent(evt);
697      }
698      return result;
699    }
700
701    @Override
702    public boolean verifyIBMPINOffset(EncryptedPIN pinUnderKd1, T kd1, T pvk,
703                                      String offset, String decTab, String pinValData,
704                                      int minPinLen) throws SMException {
705        List<Loggeable> cmdParameters = new ArrayList<>();
706        cmdParameters.add(new SimpleMsg("parameter", "account number", pinUnderKd1.getAccountNumber()));
707        cmdParameters.add(new SimpleMsg("parameter", "PIN under Data Key 1", pinUnderKd1));
708        cmdParameters.add(new SimpleMsg("parameter", "Data Key 1", kd1));
709        cmdParameters.add(new SimpleMsg("parameter", "PVK", pvk));
710        cmdParameters.add(new SimpleMsg("parameter", "Pin block format", pinUnderKd1.getPINBlockFormat()));
711        cmdParameters.add(new SimpleMsg("parameter", "decimalisation table", decTab));
712        cmdParameters.add(new SimpleMsg("parameter", "PIN validation data", pinValData));
713        cmdParameters.add(new SimpleMsg("parameter", "minimum PIN length", minPinLen));
714        cmdParameters.add(new SimpleMsg("parameter", "offset", offset));
715      LogEvent evt = new LogEvent(this, "s-m-operation");
716      evt.addMessage(new SimpleMsg("command", "Verify PIN offset", cmdParameters));
717
718      try {
719        boolean r = verifyIBMPINOffsetImpl(pinUnderKd1, kd1, pvk, offset, decTab,
720                 pinValData, minPinLen);
721        evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
722        return r;
723      } catch (Exception e) {
724        evt.addMessage(e);
725        throw e instanceof SMException ? (SMException) e : new SMException(e);
726      } finally {
727        logEvent(evt);
728      }
729    }
730
731    @Override
732    public EncryptedPIN deriveIBMPIN(String accountNo, T pvk,
733                                     String decTab, String pinValData,
734                                     int minPinLen, String offset) throws SMException {
735        List<Loggeable> cmdParameters = new ArrayList<>();
736        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
737        cmdParameters.add(new SimpleMsg("parameter", "Offset", offset));
738        cmdParameters.add(new SimpleMsg("parameter", "PVK", pvk));
739        cmdParameters.add(new SimpleMsg("parameter", "Decimalisation table", decTab));
740        cmdParameters.add(new SimpleMsg("parameter", "PIN validation data", pinValData));
741        cmdParameters.add(new SimpleMsg("parameter", "Minimum PIN length", minPinLen));
742      LogEvent evt = new LogEvent(this, "s-m-operation");
743      evt.addMessage(new SimpleMsg("command", "Derive a PIN Using the IBM Method", cmdParameters));
744      EncryptedPIN result = null;
745      try {
746        result = deriveIBMPINImpl(accountNo, pvk, decTab,  pinValData, minPinLen,  offset);
747        evt.addMessage(new SimpleMsg("result", "Derived PIN", result));
748      } catch (Exception e) {
749        evt.addMessage(e);
750        throw e instanceof SMException ? (SMException) e : new SMException(e);
751      } finally {
752        logEvent(evt);
753      }
754      return result;
755    }
756
757    @Override
758    public String calculateCVV(String accountNo, T cvkA, T cvkB,
759                               Date expDate, String serviceCode) throws SMException {
760
761        List<Loggeable> cmdParameters = new ArrayList<>();
762        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
763        cmdParameters.add(new SimpleMsg("parameter", "cvk-a", cvkA == null ? "" : cvkA));
764        cmdParameters.add(new SimpleMsg("parameter", "cvk-b", cvkB == null ? "" : cvkB));
765        cmdParameters.add(new SimpleMsg("parameter", "Exp date", expDate));
766        cmdParameters.add(new SimpleMsg("parameter", "Service code", serviceCode));
767        LogEvent evt = new LogEvent(this, "s-m-operation");
768        evt.addMessage(new SimpleMsg("command", "Calculate CVV/CVC", cmdParameters));
769        String result = null;
770        try {
771            result = calculateCVVImpl(accountNo, cvkA, cvkB, expDate, serviceCode);
772            evt.addMessage(new SimpleMsg("result", "Calculated CVV/CVC", result));
773        } catch (Exception e) {
774            evt.addMessage(e);
775            throw e instanceof SMException ? (SMException) e : new SMException(e);
776        } finally {
777            logEvent(evt);
778        }
779        return result;
780    }
781
782    @Override
783    public String calculateCVD(String accountNo, T cvkA, T cvkB,
784                               String expDate, String serviceCode) throws SMException {
785
786        List<Loggeable> cmdParameters = new ArrayList<>();
787        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
788        cmdParameters.add(new SimpleMsg("parameter", "cvk-a", cvkA == null ? "" : cvkA));
789        cmdParameters.add(new SimpleMsg("parameter", "cvk-b", cvkB == null ? "" : cvkB));
790        cmdParameters.add(new SimpleMsg("parameter", "Exp date", expDate));
791        cmdParameters.add(new SimpleMsg("parameter", "Service code", serviceCode));
792        LogEvent evt = new LogEvent(this, "s-m-operation");
793        evt.addMessage(new SimpleMsg("command", "Calculate CVV/CVC", cmdParameters));
794        String result = null;
795        try {
796            result = calculateCVDImpl(accountNo, cvkA, cvkB, expDate, serviceCode);
797            evt.addMessage(new SimpleMsg("result", "Calculated CVV/CVC", result));
798        } catch (Exception e) {
799            evt.addMessage(e);
800            throw e instanceof SMException ? (SMException) e : new SMException(e);
801        } finally {
802            logEvent(evt);
803        }
804        return result;
805    }
806
807    @Override
808    public String calculateCAVV(String accountNo, T cvk, String upn,
809                                String authrc, String sfarc) throws SMException {
810
811      List<Loggeable> cmdParameters = new ArrayList<>();
812      cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
813      cmdParameters.add(new SimpleMsg("parameter", "cvk", cvk == null ? "" : cvk));
814      cmdParameters.add(new SimpleMsg("parameter", "unpredictable number", upn));
815      cmdParameters.add(new SimpleMsg("parameter", "auth rc", authrc));
816      cmdParameters.add(new SimpleMsg("parameter", "second factor auth rc", sfarc));
817      LogEvent evt = new LogEvent(this, "s-m-operation");
818      evt.addMessage(new SimpleMsg("command", "Calculate CAVV/AAV", cmdParameters));
819      String result = null;
820      try {
821          result = calculateCAVVImpl(accountNo, cvk, upn, authrc, sfarc);
822          evt.addMessage(new SimpleMsg("result", "Calculated CAVV/AAV", result));
823      } catch (Exception e) {
824          evt.addMessage(e);
825          throw e instanceof SMException ? (SMException) e : new SMException(e);
826      } finally {
827          logEvent(evt);
828      }
829      return result;
830    }
831
832    @Override
833    public boolean verifyCVV(String accountNo , T cvkA, T cvkB,
834                            String cvv, Date expDate, String serviceCode) throws SMException {
835
836        List<Loggeable> cmdParameters = new ArrayList<>();
837        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
838        cmdParameters.add(new SimpleMsg("parameter", "cvk-a", cvkA == null ? "" : cvkA));
839        cmdParameters.add(new SimpleMsg("parameter", "cvk-b", cvkB == null ? "" : cvkB));
840        cmdParameters.add(new SimpleMsg("parameter", "CVV/CVC", cvv));
841        cmdParameters.add(new SimpleMsg("parameter", "Exp date", expDate));
842        cmdParameters.add(new SimpleMsg("parameter", "Service code", serviceCode));
843      LogEvent evt = new LogEvent(this, "s-m-operation");
844      evt.addMessage(new SimpleMsg("command", "Verify CVV/CVC", cmdParameters));
845      try {
846        boolean r = verifyCVVImpl(accountNo, cvkA, cvkB, cvv, expDate, serviceCode);
847        evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
848        return r;
849      } catch (Exception e) {
850        evt.addMessage(e);
851        throw e instanceof SMException ? (SMException) e : new SMException(e);
852      } finally {
853        logEvent(evt);
854      }
855    }
856
857    @Override
858    public boolean verifyCVD(String accountNo, T cvkA, T cvkB,
859                            String cvv, String expDate, String serviceCode) throws SMException {
860
861        List<Loggeable> cmdParameters = new ArrayList<>();
862        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
863        cmdParameters.add(new SimpleMsg("parameter", "cvk-a", cvkA == null ? "" : cvkA));
864        cmdParameters.add(new SimpleMsg("parameter", "cvk-b", cvkB == null ? "" : cvkB));
865        cmdParameters.add(new SimpleMsg("parameter", "CVV/CVC", cvv));
866        cmdParameters.add(new SimpleMsg("parameter", "Exp date", expDate));
867        cmdParameters.add(new SimpleMsg("parameter", "Service code", serviceCode));
868        LogEvent evt = new LogEvent(this, "s-m-operation");
869        evt.addMessage(new SimpleMsg("command", "Verify CVV/CVC", cmdParameters));
870        try {
871            boolean r = verifyCVVImpl(accountNo, cvkA, cvkB, cvv, expDate, serviceCode);
872            evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
873            return r;
874        } catch (Exception e) {
875            evt.addMessage(e);
876            throw e instanceof SMException ? (SMException) e : new SMException(e);
877        } finally {
878            logEvent(evt);
879        }
880    }
881
882    @Override
883    public boolean verifyCAVV(String accountNo, T cvk, String cavv,
884                              String upn, String authrc, String sfarc) throws SMException {
885
886      List<Loggeable> cmdParameters = new ArrayList<>();
887      cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
888      cmdParameters.add(new SimpleMsg("parameter", "cvk", cvk == null ? "" : cvk));
889      cmdParameters.add(new SimpleMsg("parameter", "cavv", cavv == null ? "" : cavv));
890      cmdParameters.add(new SimpleMsg("parameter", "unpredictable number", upn));
891      cmdParameters.add(new SimpleMsg("parameter", "auth rc", authrc));
892      cmdParameters.add(new SimpleMsg("parameter", "second factor auth rc", sfarc));
893      LogEvent evt = new LogEvent(this, "s-m-operation");
894      evt.addMessage(new SimpleMsg("command", "Verify CAVV/AAV", cmdParameters));
895      boolean r = false;
896      try {
897          r = verifyCAVVImpl(accountNo, cvk, cavv, upn, authrc, sfarc);
898          evt.addMessage(new SimpleMsg("result", "Verification status", r));
899      } catch (Exception e) {
900          evt.addMessage(e);
901          throw e instanceof SMException ? (SMException) e : new SMException(e);
902      } finally {
903          logEvent(evt);
904      }
905      return r;
906    }
907
908    @Override
909    public boolean verifydCVV(String accountNo, T imkac, String dcvv,
910                     Date expDate, String serviceCode, byte[] atc, MKDMethod mkdm)
911                     throws SMException {
912
913        List<Loggeable> cmdParameters = new ArrayList<>();
914        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
915        cmdParameters.add(new SimpleMsg("parameter", "imk-ac", imkac == null ? "" : imkac));
916        cmdParameters.add(new SimpleMsg("parameter", "dCVV", dcvv));
917        cmdParameters.add(new SimpleMsg("parameter", "Exp date", expDate));
918        cmdParameters.add(new SimpleMsg("parameter", "Service code", serviceCode));
919        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
920        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
921      LogEvent evt = new LogEvent(this, "s-m-operation");
922      evt.addMessage(new SimpleMsg("command", "Verify dCVV", cmdParameters));
923      try {
924        boolean r = verifydCVVImpl(accountNo, imkac, dcvv, expDate, serviceCode, atc, mkdm);
925        evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
926        return r;
927      } catch (Exception e) {
928        evt.addMessage(e);
929        throw e instanceof SMException ? (SMException) e : new SMException(e);
930      } finally {
931        logEvent(evt);
932      }
933    }
934
935    @Override
936    public boolean verifydCVV(String accountNo, T imkac, String dcvv,
937                     String expDate, String serviceCode, byte[] atc, MKDMethod mkdm)
938                     throws SMException {
939
940        if (accountNo == null || accountNo.trim().length() == 0)
941            throw new IllegalArgumentException("Account number not set.");
942
943        List<Loggeable> cmdParameters = new ArrayList<>();
944        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
945        cmdParameters.add(new SimpleMsg("parameter", "imk-ac", imkac == null ? "" : imkac));
946        cmdParameters.add(new SimpleMsg("parameter", "dCVV", dcvv));
947        cmdParameters.add(new SimpleMsg("parameter", "Exp date", expDate));
948        cmdParameters.add(new SimpleMsg("parameter", "Service code", serviceCode));
949        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
950        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
951        LogEvent evt = new LogEvent(this, "s-m-operation");
952        evt.addMessage(new SimpleMsg("command", "Verify dCVV", cmdParameters));
953        try {
954            boolean r = verifydCVVImpl(accountNo, imkac, dcvv, expDate, serviceCode, atc, mkdm);
955            evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
956            return r;
957        } catch (Exception e) {
958            evt.addMessage(e);
959            throw e instanceof SMException ? (SMException) e : new SMException(e);
960        } finally {
961            logEvent(evt);
962        }
963    }
964
965    /**
966     * @param imkcvc3 the issuer master key for generating and verifying CVC3
967     * @param accountNo The account number including BIN and the check digit
968     * @param acctSeqNo account sequence number, 2 decimal digits
969     * @param atc application transactin counter. This is used for ICC Master
970     *        Key derivation. A 2 byte value must be supplied.
971     * @param upn  unpredictable number. This is used for Session Key Generation
972     *        A 4 byte value must be supplied.
973     * @param data track data
974     * @param mkdm ICC Master Key Derivation Method. If {@code null} specified
975     *        is assumed.
976     * @param cvc3 dynamic Card Verification Code 3
977     * @return true if cvc3 is valid false if not
978     * @throws SMException
979     */
980    @Override
981    public boolean verifyCVC3(T imkcvc3, String accountNo, String acctSeqNo,
982                     byte[] atc, byte[] upn, byte[] data, MKDMethod mkdm, String cvc3)
983                     throws SMException {
984
985        List<Loggeable> cmdParameters = new ArrayList<>();
986        cmdParameters.add(new SimpleMsg("parameter", "imk-cvc3", imkcvc3 == null ? "" : imkcvc3));
987        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
988        cmdParameters.add(new SimpleMsg("parameter", "accnt seq no", acctSeqNo));
989        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
990        cmdParameters.add(new SimpleMsg("parameter", "upn", upn == null ? "" : ISOUtil.hexString(upn)));
991        cmdParameters.add(new SimpleMsg("parameter", "data", data == null ? "" : ISOUtil.hexString(data)));
992        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
993        cmdParameters.add(new SimpleMsg("parameter", "cvc3", cvc3));
994      LogEvent evt = new LogEvent(this, "s-m-operation");
995      evt.addMessage(new SimpleMsg("command", "Verify CVC3", cmdParameters));
996      try {
997        boolean r = verifyCVC3Impl(imkcvc3, accountNo, acctSeqNo, atc, upn, data, mkdm, cvc3);
998        evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
999        return r;
1000      } catch (Exception e) {
1001        evt.addMessage(e);
1002        throw e instanceof SMException ? (SMException) e : new SMException(e);
1003      } finally {
1004        logEvent(evt);
1005      }
1006    }
1007
1008    @Override
1009    public boolean verifyARQC(MKDMethod mkdm, SKDMethod skdm, T imkac
1010            ,String accoutNo, String acctSeqNo, byte[] arqc, byte[] atc
1011            ,byte[] upn, byte[] txnData) throws SMException {
1012
1013        List<Loggeable> cmdParameters = new ArrayList<>();
1014        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
1015        cmdParameters.add(new SimpleMsg("parameter", "skd method", skdm));
1016        cmdParameters.add(new SimpleMsg("parameter", "imk-ac", imkac));
1017        cmdParameters.add(new SimpleMsg("parameter", "account number", accoutNo));
1018        cmdParameters.add(new SimpleMsg("parameter", "accnt seq no", acctSeqNo));
1019        cmdParameters.add(new SimpleMsg("parameter", "arqc", arqc == null ? "" : ISOUtil.hexString(arqc)));
1020        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
1021        cmdParameters.add(new SimpleMsg("parameter", "upn", upn == null ? "" : ISOUtil.hexString(upn)));
1022        cmdParameters.add(new SimpleMsg("parameter", "txn data", txnData == null ? "" : ISOUtil.hexString(txnData)));
1023      LogEvent evt = new LogEvent(this, "s-m-operation");
1024      evt.addMessage(new SimpleMsg("command", "Verify ARQC/TC/AAC", cmdParameters));
1025      try {
1026        boolean r = verifyARQCImpl(mkdm, skdm, imkac, accoutNo, acctSeqNo, arqc, atc, upn, txnData);
1027        evt.addMessage(new SimpleMsg("result", "Verification status", r ? "valid" : "invalid"));
1028        return r;
1029      } catch (Exception e) {
1030        evt.addMessage(e);
1031        throw e instanceof SMException ? (SMException) e : new SMException(e);
1032      } finally {
1033        logEvent(evt);
1034      }
1035    }
1036
1037    @Override
1038    public byte[] generateARPC(MKDMethod mkdm, SKDMethod skdm, T imkac
1039            ,String accoutNo, String acctSeqNo, byte[] arqc, byte[] atc, byte[] upn
1040            ,ARPCMethod arpcMethod, byte[] arc, byte[] propAuthData)
1041            throws SMException {
1042
1043        List<Loggeable> cmdParameters = new ArrayList<>();
1044        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
1045        cmdParameters.add(new SimpleMsg("parameter", "skd method", skdm));
1046        cmdParameters.add(new SimpleMsg("parameter", "imk-ac", imkac));
1047        cmdParameters.add(new SimpleMsg("parameter", "account number", accoutNo));
1048        cmdParameters.add(new SimpleMsg("parameter", "accnt seq no", acctSeqNo));
1049        cmdParameters.add(new SimpleMsg("parameter", "arqc", arqc == null ? "" : ISOUtil.hexString(arqc)));
1050        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
1051        cmdParameters.add(new SimpleMsg("parameter", "upn", upn == null ? "" : ISOUtil.hexString(upn)));
1052        cmdParameters.add(new SimpleMsg("parameter", "arpc gen. method", arpcMethod));
1053        cmdParameters.add(new SimpleMsg("parameter", "auth. rc", arc == null ? "" : ISOUtil.hexString(arc)));
1054        cmdParameters.add(new SimpleMsg("parameter", "prop auth. data"
1055                , propAuthData == null ? "" : ISOUtil.hexString(propAuthData))
1056        );
1057      LogEvent evt = new LogEvent(this, "s-m-operation");
1058      evt.addMessage(new SimpleMsg("command", "Genarate ARPC", cmdParameters));
1059      try {
1060        byte[] result = generateARPCImpl(mkdm, skdm, imkac, accoutNo, acctSeqNo
1061            , arqc, atc, upn, arpcMethod, arc, propAuthData);
1062        evt.addMessage(new SimpleMsg("result", "Generated ARPC", result));
1063        return result;
1064      } catch (Exception e) {
1065        evt.addMessage(e);
1066        throw e instanceof SMException ? (SMException) e : new SMException(e);
1067      } finally {
1068        logEvent(evt);
1069      }
1070    }
1071
1072    @Override
1073    public byte[] verifyARQCGenerateARPC(MKDMethod mkdm, SKDMethod skdm, T imkac
1074            ,String accoutNo, String acctSeqNo, byte[] arqc, byte[] atc, byte[] upn
1075            ,byte[] txnData, ARPCMethod arpcMethod, byte[] arc, byte[] propAuthData)
1076            throws SMException {
1077
1078        List<Loggeable> cmdParameters = new ArrayList<>();
1079        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
1080        cmdParameters.add(new SimpleMsg("parameter", "skd method", skdm));
1081        cmdParameters.add(new SimpleMsg("parameter", "imk-ac", imkac));
1082        cmdParameters.add(new SimpleMsg("parameter", "account number", accoutNo));
1083        cmdParameters.add(new SimpleMsg("parameter", "accnt seq no", acctSeqNo));
1084        cmdParameters.add(new SimpleMsg("parameter", "arqc", arqc == null ? "" : ISOUtil.hexString(arqc)));
1085        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
1086        cmdParameters.add(new SimpleMsg("parameter", "upn", upn == null ? "" : ISOUtil.hexString(upn)));
1087        cmdParameters.add(new SimpleMsg("parameter", "txn data", txnData == null ? "" : ISOUtil.hexString(txnData)));
1088        cmdParameters.add(new SimpleMsg("parameter", "arpc gen. method", arpcMethod));
1089        cmdParameters.add(new SimpleMsg("parameter", "auth. rc", arc == null ? "" : ISOUtil.hexString(arc)));
1090        cmdParameters.add(new SimpleMsg("parameter", "prop auth. data",
1091                propAuthData == null ? "" : ISOUtil.hexString(propAuthData))
1092        );
1093      LogEvent evt = new LogEvent(this, "s-m-operation");
1094      evt.addMessage(new SimpleMsg("command", "Genarate ARPC", cmdParameters));
1095      try {
1096            byte[] result = verifyARQCGenerateARPCImpl(
1097                      mkdm, skdm, imkac, accoutNo, acctSeqNo, arqc, atc, upn
1098                    , txnData, arpcMethod, arc, propAuthData
1099            );
1100        evt.addMessage(new SimpleMsg("result", "ARPC", result == null ? "" : ISOUtil.hexString(result)));
1101        return result;
1102      } catch (Exception e) {
1103        evt.addMessage(e);
1104        throw e instanceof SMException ? (SMException) e : new SMException(e);
1105      } finally {
1106        logEvent(evt);
1107      }
1108    }
1109
1110    @Override
1111    public byte[] generateSM_MAC(MKDMethod mkdm, SKDMethod skdm
1112            ,T imksmi, String accountNo, String acctSeqNo
1113            ,byte[] atc, byte[] arqc, byte[] data) throws SMException {
1114
1115        List<Loggeable> cmdParameters = new ArrayList<>();
1116        cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
1117        cmdParameters.add(new SimpleMsg("parameter", "skd method", skdm));
1118        cmdParameters.add(new SimpleMsg("parameter", "imk-smi", imksmi));
1119        cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
1120        cmdParameters.add(new SimpleMsg("parameter", "accnt seq no", acctSeqNo));
1121        cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
1122        cmdParameters.add(new SimpleMsg("parameter", "arqc", arqc == null ? "" : ISOUtil.hexString(arqc)));
1123        cmdParameters.add(new SimpleMsg("parameter", "data", data == null ? "" : ISOUtil.hexString(data)));
1124      LogEvent evt = new LogEvent(this, "s-m-operation");
1125      evt.addMessage(new SimpleMsg("command", "Generate Secure Messaging MAC", cmdParameters));
1126      try {
1127        byte[] mac = generateSM_MACImpl(mkdm, skdm, imksmi, accountNo, acctSeqNo, atc, arqc, data);
1128        evt.addMessage(new SimpleMsg("result", "Generated MAC", mac!=null ? ISOUtil.hexString(mac) : ""));
1129        return mac;
1130      } catch (Exception e) {
1131        evt.addMessage(e);
1132        throw e instanceof SMException ? (SMException) e : new SMException(e);
1133      } finally {
1134        logEvent(evt);
1135      }
1136    }
1137
1138    @Override
1139    public Pair<EncryptedPIN,byte[]> translatePINGenerateSM_MAC(MKDMethod mkdm
1140           ,SKDMethod skdm, PaddingMethod padm, T imksmi
1141           ,String accountNo, String acctSeqNo, byte[] atc, byte[] arqc
1142           ,byte[] data, EncryptedPIN currentPIN, EncryptedPIN newPIN
1143           ,T kd1, T imksmc, T imkac
1144           ,byte destinationPINBlockFormat) throws SMException {
1145
1146      List<Loggeable> cmdParameters = new ArrayList<>();
1147      cmdParameters.add(new SimpleMsg("parameter", "mkd method", mkdm));
1148      cmdParameters.add(new SimpleMsg("parameter", "skd method", skdm));
1149      if (padm!=null)
1150        cmdParameters.add(new SimpleMsg("parameter", "padding method", padm));
1151      cmdParameters.add(new SimpleMsg("parameter", "imk-smi", imksmi));
1152      cmdParameters.add(new SimpleMsg("parameter", "account number", accountNo));
1153      cmdParameters.add(new SimpleMsg("parameter", "accnt seq no", acctSeqNo));
1154      cmdParameters.add(new SimpleMsg("parameter", "atc", atc == null ? "" : ISOUtil.hexString(atc)));
1155      cmdParameters.add(new SimpleMsg("parameter", "arqc", arqc == null ? "" : ISOUtil.hexString(arqc)));
1156      cmdParameters.add(new SimpleMsg("parameter", "data", data == null ? "" : ISOUtil.hexString(data)));
1157      cmdParameters.add(new SimpleMsg("parameter", "Current Encrypted PIN", currentPIN));
1158      cmdParameters.add(new SimpleMsg("parameter", "New Encrypted PIN", newPIN));
1159      cmdParameters.add(new SimpleMsg("parameter", "Source PIN Encryption Key", kd1));
1160      cmdParameters.add(new SimpleMsg("parameter", "imk-smc", imksmc));
1161      if (imkac!=null)
1162        cmdParameters.add(new SimpleMsg("parameter", "imk-ac", imkac));
1163      cmdParameters.add(new SimpleMsg("parameter", "Destination PIN Block Format", destinationPINBlockFormat));
1164      LogEvent evt = new LogEvent(this, "s-m-operation");
1165      evt.addMessage(new SimpleMsg("command", "Translate PIN block format and Generate Secure Messaging MAC"
1166                    ,cmdParameters)
1167      );
1168      try {
1169            Pair<EncryptedPIN,byte[]> r = translatePINGenerateSM_MACImpl(mkdm, skdm
1170                ,padm, imksmi, accountNo, acctSeqNo, atc, arqc, data, currentPIN
1171                ,newPIN, kd1, imksmc, imkac, destinationPINBlockFormat
1172            );
1173            List<Loggeable> cmdResults = new ArrayList<>();
1174            cmdResults.add(new SimpleMsg("result", "Translated PIN block", r.getValue0()));
1175            cmdResults.add(new SimpleMsg("result", "Generated MAC", r.getValue1() == null ? "" : ISOUtil.hexString(r.getValue1())));
1176            evt.addMessage(new SimpleMsg("results", "Complex results", cmdResults));
1177            return r;
1178      } catch (Exception e) {
1179        evt.addMessage(e);
1180        throw e instanceof SMException ? (SMException) e : new SMException(e);
1181      } finally {
1182        logEvent(evt);
1183      }
1184    }
1185
1186    /**
1187     * Encrypt Data Block.
1188     *
1189     * @param cipherMode block cipher mode
1190     * @param kd DEK or ZEK key used to encrypt data
1191     * @param data data to be encrypted
1192     * @param iv initial vector
1193     * @return encrypted data
1194     * @throws SMException
1195     */
1196    @Override
1197    public byte[] encryptData(CipherMode cipherMode, SecureDESKey kd
1198            ,byte[] data, byte[] iv) throws SMException {
1199
1200        List<Loggeable> cmdParameters = new ArrayList<>();
1201        cmdParameters.add(new SimpleMsg("parameter", "Block Cipher Mode", cipherMode));
1202        if(kd != null)
1203            cmdParameters.add(new SimpleMsg("parameter", "Data key", kd));
1204        if(data != null)
1205            cmdParameters.add(new SimpleMsg("parameter", "Data", ISOUtil.hexString(data)));
1206        if(iv != null)
1207            cmdParameters.add(new SimpleMsg("parameter", "Initialization Vector", ISOUtil.hexString(iv)));
1208
1209        LogEvent evt = new LogEvent(this, "s-m-operation");
1210        evt.addMessage(new SimpleMsg("command", "Encrypt Data", cmdParameters));
1211        byte[] encData = null;
1212        try {
1213            encData = encryptDataImpl(cipherMode, kd, data, iv);
1214            List<Loggeable> r = new ArrayList<>();
1215            r.add(new SimpleMsg("result", "Encrypted Data", encData));
1216            if(iv != null)
1217                r.add(new SimpleMsg("result", "Initialization Vector", iv));
1218            evt.addMessage(new SimpleMsg("results", r));
1219        } catch (Exception e) {
1220            evt.addMessage(e);
1221            throw e instanceof SMException ? (SMException) e : new SMException(e);
1222        } finally {
1223            logEvent(evt);
1224        }
1225        return encData;
1226    }
1227
1228    /**
1229     * Decrypt Data Block.
1230     *
1231     * @param cipherMode block cipher mode
1232     * @param kd DEK or ZEK key used to decrypt data
1233     * @param data data to be decrypted
1234     * @param iv initial vector
1235     * @return decrypted data
1236     * @throws SMException
1237     */
1238    @Override
1239    public byte[] decryptData(CipherMode cipherMode, SecureDESKey kd
1240            ,byte[] data, byte[] iv) throws SMException {
1241
1242        List<Loggeable> cmdParameters = new ArrayList<>();
1243        cmdParameters.add(new SimpleMsg("parameter", "Block Cipher Mode", cipherMode));
1244        if(kd != null)
1245            cmdParameters.add(new SimpleMsg("parameter", "Data key", kd));
1246        if(data != null)
1247            cmdParameters.add(new SimpleMsg("parameter", "Data", ISOUtil.hexString(data)));
1248        if(iv != null)
1249            cmdParameters.add(new SimpleMsg("parameter", "Initialization Vector", ISOUtil.hexString(iv)));
1250
1251        LogEvent evt = new LogEvent(this, "s-m-operation");
1252        evt.addMessage(new SimpleMsg("command", "Decrypt Data", cmdParameters));
1253        byte[] decData = null;
1254        try {
1255            decData = decryptDataImpl(cipherMode, kd, data, iv);
1256            List<Loggeable> r = new ArrayList<>();
1257            r.add(new SimpleMsg("result", "Decrypted Data", decData));
1258            if(iv != null)
1259                r.add(new SimpleMsg("result", "Initialization Vector", iv));
1260            evt.addMessage(new SimpleMsg("results", r));
1261        } catch (Exception e) {
1262            evt.addMessage(e);
1263            throw e instanceof SMException ? (SMException) e : new SMException(e);
1264        } finally {
1265            logEvent(evt);
1266        }
1267        return decData;
1268    }
1269
1270    @Override
1271    public byte[] generateCBC_MAC(byte[] data, T kd) throws SMException {
1272        List<Loggeable> cmdParameters = new ArrayList<>();
1273        cmdParameters.add(new SimpleMsg("parameter", "data", data));
1274        cmdParameters.add(new SimpleMsg("parameter", "data key", kd));
1275        LogEvent evt = new LogEvent(this, "s-m-operation");
1276        evt.addMessage(new SimpleMsg("command", "Generate CBC-MAC", cmdParameters));
1277        byte[] result = null;
1278        try {
1279            result = generateCBC_MACImpl(data, kd);
1280            evt.addMessage(new SimpleMsg("result", "CBC-MAC", result));
1281        } catch (Exception e) {
1282            evt.addMessage(e);
1283            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1284        } finally {
1285            logEvent(evt);
1286        }
1287        return  result;
1288    }
1289
1290    @Override
1291    public byte[] generateEDE_MAC(byte[] data, T kd) throws SMException {
1292        List<Loggeable> cmdParameters = new ArrayList<>();
1293        cmdParameters.add(new SimpleMsg("parameter", "data", data));
1294        cmdParameters.add(new SimpleMsg("parameter", "data key", kd));
1295        LogEvent evt = new LogEvent(this, "s-m-operation");
1296        evt.addMessage(new SimpleMsg("command", "Generate EDE-MAC", cmdParameters));
1297        byte[] result = null;
1298        try {
1299            result = generateEDE_MACImpl(data, kd);
1300            evt.addMessage(new SimpleMsg("result", "EDE-MAC", result));
1301        } catch (Exception e) {
1302            evt.addMessage(e);
1303            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1304        } finally {
1305            logEvent(evt);
1306        }
1307        return  result;
1308    }
1309
1310    @Override
1311    public SecureDESKey translateKeyFromOldLMK(SecureDESKey kd) throws SMException {
1312        List<Loggeable> cmdParameters = new ArrayList<>();
1313        cmdParameters.add(new SimpleMsg("parameter", "Key under old LMK", kd));
1314        LogEvent evt = new LogEvent(this, "s-m-operation");
1315        evt.addMessage(new SimpleMsg("command", "Translate Key from old to new LMK", cmdParameters));
1316        SecureDESKey result = null;
1317        try {
1318            result = translateKeyFromOldLMKImpl(kd);
1319            evt.addMessage(new SimpleMsg("result", "Translated Key under new LMK", result));
1320        } catch (Exception e) {
1321            evt.addMessage(e);
1322            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1323        } finally {
1324            logEvent(evt);
1325        }
1326        return  result;
1327    }
1328
1329    @Override
1330    public SecureKey translateKeyFromOldLMK(SecureKey key, SecureKeySpec keySpec) throws SMException {
1331        List<Loggeable> cmdParameters = new ArrayList<>();
1332        cmdParameters.add(new SimpleMsg("parameter", "Key under old LMK", key));
1333        cmdParameters.add(new SimpleMsg("parameter", "Key Specification", keySpec));
1334        LogEvent evt = new LogEvent(this, "s-m-operation");
1335        evt.addMessage(new SimpleMsg("command", "Translate Key from old to new LMK", cmdParameters));
1336        SecureKey result = null;
1337        try {
1338            result = translateKeyFromOldLMKImpl(key, keySpec);
1339            evt.addMessage(new SimpleMsg("result", "Translated Key under new LMK", result));
1340        } catch (Exception e) {
1341            evt.addMessage(e);
1342            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1343        } finally {
1344            logEvent(evt);
1345        }
1346        return  result;
1347    }
1348
1349    @Override
1350    public Pair<PublicKey, SecurePrivateKey> generateKeyPair(AlgorithmParameterSpec spec)
1351            throws SMException {
1352        List<Loggeable> cmdParameters = new ArrayList<>();
1353        cmdParameters.add(new SimpleMsg("parameter", "Algorithm Parameter Spec", spec.getClass().getName()));
1354
1355        LogEvent evt = new LogEvent(this, "s-m-operation");
1356        evt.addMessage(new SimpleMsg("command", "Generate public/private key pair", cmdParameters));
1357        Pair<PublicKey, SecurePrivateKey> result = null;
1358        try {
1359            result = generateKeyPairImpl(spec);
1360            List<Loggeable> cmdResults = new ArrayList<>();
1361            cmdResults.add(new SimpleMsg("result", "Public Key", result.getValue0().getEncoded()));
1362            cmdResults.add(new SimpleMsg("result", "Private Key", result.getValue1().getKeyBytes()));
1363            evt.addMessage(new SimpleMsg("results", "Complex results", cmdResults));
1364        } catch (Exception e) {
1365            evt.addMessage(e);
1366            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1367        } finally {
1368            logEvent(evt);
1369        }
1370        return result;
1371    }
1372
1373    @Override
1374    public Pair<PublicKey, SecureKey> generateKeyPair(SecureKeySpec keySpec)
1375            throws SMException {
1376        List<Loggeable> cmdParameters = new ArrayList<>();
1377        cmdParameters.add(new SimpleMsg("parameter", "Key Pair Specification", keySpec));
1378
1379        LogEvent evt = new LogEvent(this, "s-m-operation");
1380        evt.addMessage(new SimpleMsg("command", "Generate public/private key pair", cmdParameters));
1381        Pair<PublicKey, SecureKey> result = null;
1382        try {
1383            result = generateKeyPairImpl(keySpec);
1384            List<Loggeable> cmdResults = new ArrayList<>();
1385            cmdResults.add(new SimpleMsg("result", "Public Key", result.getValue0().getEncoded()));
1386            cmdResults.add(new SimpleMsg("result", "Private Key", result.getValue1().getKeyBytes()));
1387            evt.addMessage(new SimpleMsg("results", "Complex results", cmdResults));
1388        } catch (Exception e) {
1389            evt.addMessage(e);
1390            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1391        } finally {
1392            logEvent(evt);
1393        }
1394        return result;
1395    }
1396
1397    @Override
1398    public byte[] calculateSignature(MessageDigest hash, SecureKey privateKey
1399            ,byte[] data) throws SMException {
1400        List<Loggeable> cmdParameters = new ArrayList<>();
1401        cmdParameters.add(new SimpleMsg("parameter", "Hash Identifier", hash));
1402        cmdParameters.add(new SimpleMsg("parameter", "Private Key", privateKey));
1403        cmdParameters.add(new SimpleMsg("parameter", "data", data));
1404
1405        LogEvent evt = new LogEvent(this, "s-m-operation");
1406        evt.addMessage(new SimpleMsg("command", "Generate data signature", cmdParameters));
1407        byte[] result = null;
1408        try {
1409            result = calculateSignatureImpl(hash, privateKey, data);
1410            evt.addMessage(new SimpleMsg("result", "Data Signature", result));
1411        } catch (Exception e) {
1412            evt.addMessage(e);
1413            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1414        } finally {
1415            logEvent(evt);
1416        }
1417        return result;
1418    }
1419
1420    @Override
1421    public byte[] encryptData(SecureKey encKey, byte[] data
1422            , AlgorithmParameterSpec algspec, byte[] iv) throws SMException {
1423        List<Loggeable> cmdParameters = new ArrayList<>();
1424        cmdParameters.add(new SimpleMsg("parameter", "Encription Key", encKey));
1425        cmdParameters.add(new SimpleMsg("parameter", "Data", ISOUtil.hexString(data)));
1426        if (algspec != null)
1427            cmdParameters.add(new SimpleMsg("parameter", "Algorithm Spec", algspec));
1428        if (iv != null)
1429            cmdParameters.add(new SimpleMsg("parameter", "Initialization Vector", ISOUtil.hexString(iv)));
1430        LogEvent evt = new LogEvent(this, "s-m-operation");
1431        evt.addMessage(new SimpleMsg("command", "Encrypt Data", cmdParameters));
1432        byte[] result = null;
1433        try {
1434            result = encryptDataImpl(encKey, data, algspec, iv);
1435            List<Loggeable> r = new ArrayList<>();
1436            r.add(new SimpleMsg("result", "Encrypted Data", result));
1437            if (iv != null)
1438                r.add(new SimpleMsg("result", "Initialization Vector", iv));
1439            evt.addMessage(new SimpleMsg("results", r));
1440        } catch (SMException ex) {
1441            evt.addMessage(ex);
1442            throw ex;
1443        } catch (RuntimeException ex) {
1444            evt.addMessage(ex);
1445            throw new SMException(ex);
1446        } finally {
1447            logEvent(evt);
1448        }
1449        return result;
1450    }
1451
1452    @Override
1453    public byte[] decryptData(SecureKey privKey, byte[] data
1454            , AlgorithmParameterSpec algspec, byte[] iv) throws SMException {
1455        List<Loggeable> cmdParameters = new ArrayList<>();
1456        cmdParameters.add(new SimpleMsg("parameter", "Decription Key", privKey));
1457        cmdParameters.add(new SimpleMsg("parameter", "Encrypted Data", ISOUtil.hexString(data)));
1458        if (algspec != null)
1459            cmdParameters.add(new SimpleMsg("parameter", "Algorithm Spec", algspec));
1460        if (iv != null)
1461            cmdParameters.add(new SimpleMsg("parameter", "Initialization Vector", ISOUtil.hexString(iv)));
1462        LogEvent evt = new LogEvent(this, "s-m-operation");
1463        evt.addMessage(new SimpleMsg("command", "Decrypt Data", cmdParameters));
1464        byte[] result = null;
1465        try {
1466            result = decryptDataImpl(privKey, data, algspec, iv);
1467            List<Loggeable> r = new ArrayList<>();
1468            r.add(new SimpleMsg("result", "Decrypted Data", result));
1469            if (iv != null)
1470                r.add(new SimpleMsg("result", "Initialization Vector", iv));
1471            evt.addMessage(new SimpleMsg("results", r));
1472        } catch (SMException ex) {
1473            evt.addMessage(ex);
1474            throw ex;
1475        } catch (RuntimeException ex) {
1476            evt.addMessage(ex);
1477            throw new SMException(ex);
1478        } finally {
1479            logEvent(evt);
1480        }
1481        return result;
1482    }
1483
1484    @Override
1485    public void eraseOldLMK () throws SMException {
1486        List<Loggeable> cmdParameters = new ArrayList<>();
1487        LogEvent evt = new LogEvent(this, "s-m-operation");
1488        evt.addMessage(new SimpleMsg("command", "Erase the key change storage", cmdParameters));
1489        try {
1490            eraseOldLMKImpl();
1491        } catch (Exception e) {
1492            evt.addMessage(e);
1493            throw  e instanceof SMException ? (SMException) e : new SMException(e);
1494        } finally {
1495            logEvent(evt);
1496        }
1497    }
1498
1499    /**
1500     * Your SMAdapter should override this method if it has this functionality
1501     * @param keyLength
1502     * @param keyType
1503     * @return generated key
1504     * @throws SMException
1505     */
1506    protected SecureDESKey generateKeyImpl (short keyLength, String keyType) throws SMException {
1507        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1508    }
1509
1510    /**
1511     * Your SMAdapter should override this method if it has this functionality.
1512     *
1513     * @param keySpec
1514     * @return generated key
1515     * @throws SMException
1516     */
1517    protected SecureKey generateKeyImpl(SecureKeySpec keySpec) throws SMException {
1518        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
1519    }
1520
1521    /**
1522     * Your SMAdapter should override this method if it has this functionality
1523     * @param kd
1524     * @return generated Key Check Value
1525     * @throws SMException
1526     */
1527    protected byte[] generateKeyCheckValueImpl(T kd) throws SMException {
1528        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1529    }
1530
1531    /**
1532     * Your SMAdapter should override this method if it has this functionality
1533     * @param key
1534     * @param destKeyScheme
1535     * @return translated key with {@code destKeyScheme} scheme
1536     * @throws SMException
1537     */
1538    protected SecureDESKey translateKeySchemeImpl(SecureDESKey key, KeyScheme destKeyScheme)
1539            throws SMException {
1540        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1541    }
1542
1543    /**
1544     * Your SMAdapter should override this method if it has this functionality
1545     * @param keyLength
1546     * @param keyType
1547     * @param encryptedKey
1548     * @param kek
1549     * @param checkParity
1550     * @return imported key
1551     * @throws SMException
1552     */
1553    protected SecureDESKey importKeyImpl(short keyLength, String keyType, byte[] encryptedKey,
1554            SecureDESKey kek, boolean checkParity) throws SMException {
1555        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1556    }
1557
1558    /**
1559     * Your SMAdapter should override this method if it has this functionality.
1560     *
1561     * @param kek
1562     * @param key
1563     * @param keySpec
1564     * @param checkParity
1565     * @return imported key
1566     * @throws SMException
1567     */
1568    protected SecureKey importKeyImpl(SecureKey kek, SecureKey key,
1569            SecureKeySpec keySpec, boolean checkParity) throws SMException {
1570        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
1571    }
1572
1573    /**
1574     * Your SMAdapter should override this method if it has this functionality
1575     * @param key
1576     * @param kek
1577     * @return exported key
1578     * @throws SMException
1579     */
1580    protected byte[] exportKeyImpl(SecureDESKey key, SecureDESKey kek) throws SMException {
1581        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1582    }
1583
1584    /**
1585     * Your SMAdapter should override this method if it has this functionality.
1586     *
1587     * @param kek
1588     * @param key
1589     * @param keySpec
1590     * @return exported key
1591     * @throws SMException
1592     */
1593    protected SecureKey exportKeyImpl(SecureKey kek, SecureKey key
1594            , SecureKeySpec keySpec) throws SMException {
1595        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
1596    }
1597
1598    /**
1599     * Your SMAdapter should override this method if it has this functionality
1600     * @param pin
1601     * @param accountNumber
1602     * @return encrypted PIN under LMK
1603     * @throws SMException
1604     */
1605    protected EncryptedPIN encryptPINImpl (String pin, String accountNumber) throws SMException {
1606        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1607    }
1608
1609    /**
1610     * Your SMAdapter should override this method if it has this functionality.
1611     *
1612     * @param pin
1613     * @param accountNumber
1614     * @param pek
1615     * @return encrypted PIN under PEK.
1616     * @throws SMException
1617     */
1618    protected EncryptedPIN encryptPINImpl(String pin, String accountNumber, T pek) throws SMException {
1619        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1620    }
1621
1622    /**
1623     * Your SMAdapter should override this method if it has this functionality
1624     * @param pinUnderLmk
1625     * @return clear pin as entered by card holder
1626     * @throws SMException
1627     */
1628    protected String decryptPINImpl (EncryptedPIN pinUnderLmk) throws SMException {
1629        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1630    }
1631
1632    /**
1633     * Your SMAdapter should override this method if it has this functionality
1634     * @param pinUnderKd1
1635     * @param kd1
1636     * @return imported pin
1637     * @throws SMException
1638     */
1639    protected EncryptedPIN importPINImpl(EncryptedPIN pinUnderKd1, T kd1) throws SMException {
1640        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1641    }
1642
1643    /**
1644     * Your SMAdapter should override this method if it has this functionality
1645     * @param pinUnderKd1
1646     * @param kd1
1647     * @param kd2
1648     * @param destinationPINBlockFormat
1649     * @return translated pin
1650     * @throws SMException
1651     */
1652    protected EncryptedPIN translatePINImpl(EncryptedPIN pinUnderKd1, T kd1,
1653            T kd2, byte destinationPINBlockFormat) throws SMException {
1654        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1655    }
1656
1657    /**
1658     * Your SMAdapter should override this method if it has this functionality
1659     * @deprecated
1660     * @param pinUnderDuk
1661     * @param ksn
1662     * @param bdk
1663     * @return imported pin
1664     * @throws SMException
1665     */
1666    @Deprecated
1667    protected EncryptedPIN importPINImpl(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
1668            T bdk) throws SMException {
1669        return importPINImpl(pinUnderDuk,ksn,bdk,false);
1670    }
1671
1672    /**
1673     * Your SMAdapter should override this method if it has this functionality
1674     * @param pinUnderDuk
1675     * @param ksn
1676     * @param bdk
1677     * @param tdes
1678     * @return imported pin
1679     * @throws SMException
1680     */
1681    protected EncryptedPIN importPINImpl(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
1682            T bdk, boolean tdes) throws SMException {
1683        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1684    }
1685
1686    /**
1687     * Your SMAdapter should override this method if it has this functionality
1688     * @deprecated
1689     * @param pinUnderDuk
1690     * @param ksn
1691     * @param bdk
1692     * @param kd2
1693     * @param destinationPINBlockFormat
1694     * @return translated pin
1695     * @throws SMException
1696     */
1697    @Deprecated
1698    protected EncryptedPIN translatePINImpl(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
1699            T bdk, T kd2, byte destinationPINBlockFormat) throws SMException {
1700        return translatePINImpl(pinUnderDuk,ksn,bdk,kd2,destinationPINBlockFormat,false);
1701    }
1702
1703    /**
1704     * Your SMAdapter should override this method if it has this functionality
1705     * @param pinUnderDuk
1706     * @param ksn
1707     * @param bdk
1708     * @param kd2
1709     * @param tdes
1710     * @param destinationPINBlockFormat
1711     * @return translated pin
1712     * @throws SMException
1713     */
1714    protected EncryptedPIN translatePINImpl(EncryptedPIN pinUnderDuk, KeySerialNumber ksn,
1715            T bdk, T kd2, byte destinationPINBlockFormat,
1716            boolean tdes) throws SMException {
1717        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1718    }
1719
1720    /**
1721     * Your SMAdapter should override this method if it has this functionality
1722     * @param pinUnderLmk
1723     * @param kd2
1724     * @param destinationPINBlockFormat
1725     * @return exported pin
1726     * @throws SMException
1727     */
1728    protected EncryptedPIN exportPINImpl(EncryptedPIN pinUnderLmk, T kd2,
1729            byte destinationPINBlockFormat) throws SMException {
1730        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1731    }
1732
1733    /**
1734     * Your SMAdapter should override this method if it has this functionality
1735     * @param accountNumber
1736     * @param pinLen
1737     * @param excludes
1738     * @return generated PIN under LMK
1739     * @throws SMException
1740     */
1741    protected EncryptedPIN generatePINImpl(String accountNumber, int pinLen, List<String> excludes) throws
1742            SMException {
1743        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1744    }
1745
1746    /**
1747     * Your SMAdapter should override this method if it has this functionality
1748     * @param accountNo
1749     * @param pinUnderKd1
1750     * @param kd1
1751     * @param template
1752     * @param fields
1753     * @throws SMException
1754     */
1755    protected void printPINImpl(String accountNo, EncryptedPIN pinUnderKd1, T kd1
1756                             ,String template, Map<String, String> fields) throws SMException {
1757        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1758    }
1759
1760    /**
1761     * Your SMAdapter should override this method if it has this functionality
1762     * @param pinUnderLMK
1763     * @param pvkA
1764     * @param pvkB
1765     * @param pvkIdx
1766     * @param excludes
1767     * @return PVV (VISA PIN Verification Value)
1768     * @throws SMException
1769     */
1770    protected String calculatePVVImpl(EncryptedPIN pinUnderLMK,
1771                       T pvkA, T pvkB, int pvkIdx, List<String> excludes)
1772            throws SMException {
1773        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1774    }
1775
1776    /**
1777     * Your SMAdapter should override this method if it has this functionality
1778     * @param pinUnderKd1
1779     * @param kd1
1780     * @param pvkA
1781     * @param pvkB
1782     * @param pvkIdx
1783     * @param excludes
1784     * @return PVV (VISA PIN Verification Value)
1785     * @throws SMException
1786     */
1787    protected String calculatePVVImpl(EncryptedPIN pinUnderKd1, T kd1,
1788                       T pvkA, T pvkB, int pvkIdx,
1789                       List<String> excludes) throws SMException {
1790        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1791    }
1792
1793    /**
1794     * Your SMAdapter should override this method if it has this functionality
1795     * @param pinUnderKd
1796     * @param kd
1797     * @param pvkA
1798     * @param pvkB
1799     * @param pvki
1800     * @param pvv
1801     * @return true if pin is valid false if not
1802     * @throws SMException
1803     */
1804    protected boolean verifyPVVImpl(EncryptedPIN pinUnderKd, T kd, T pvkA,
1805                        T pvkB, int pvki, String pvv) throws SMException {
1806        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1807    }
1808
1809    /**
1810     * Your SMAdapter should override this method if it has this functionality
1811     * @param pinUnderLmk
1812     * @param pvk
1813     * @param decTab
1814     * @param pinValData
1815     * @param minPinLen
1816     * @param excludes
1817     * @return IBM PIN Offset
1818     * @throws SMException
1819     */
1820    protected String calculateIBMPINOffsetImpl(EncryptedPIN pinUnderLmk, T pvk,
1821                              String decTab, String pinValData, int minPinLen,
1822                              List<String> excludes) throws SMException {
1823        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1824    }
1825
1826    /**
1827     * Your SMAdapter should override this method if it has this functionality
1828     * @param pinUnderKd1
1829     * @param kd1
1830     * @param pvk
1831     * @param decTab
1832     * @param pinValData
1833     * @param minPinLen
1834     * @param excludes
1835     * @return IBM PIN Offset
1836     * @throws SMException
1837     */
1838    protected String calculateIBMPINOffsetImpl(EncryptedPIN pinUnderKd1, T kd1,
1839                              T pvk, String decTab, String pinValData,
1840                              int minPinLen, List<String> excludes)
1841            throws SMException {
1842        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1843    }
1844
1845    /**
1846     * Your SMAdapter should override this method if it has this functionality
1847     * @param pinUnderKd
1848     * @param kd
1849     * @param pvk
1850     * @param offset
1851     * @param decTab
1852     * @param pinValData
1853     * @param minPinLen
1854     * @return true if pin is valid false if not
1855     * @throws SMException
1856     */
1857    protected boolean verifyIBMPINOffsetImpl(EncryptedPIN pinUnderKd, T kd
1858                            ,T pvk, String offset, String decTab
1859                            ,String pinValData, int minPinLen) throws SMException {
1860        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1861    }
1862
1863    /**
1864     * Your SMAdapter should override this method if it has this functionality
1865     * @param accountNo
1866     * @param pvk
1867     * @param decTab
1868     * @param pinValData
1869     * @param minPinLen
1870     * @param offset
1871     * @return derived PIN under LMK
1872     * @throws SMException
1873     */
1874    protected EncryptedPIN deriveIBMPINImpl(String accountNo, T pvk, String decTab
1875                                , String pinValData, int minPinLen, String offset)
1876            throws SMException {
1877        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1878    }
1879
1880    /**
1881     * Your SMAdapter should override this method if it has this functionality
1882     * @param accountNo
1883     * @param cvkA
1884     * @param cvkB
1885     * @param expDate
1886     * @param serviceCode
1887     * @return Card Verification Code/Value
1888     * @throws SMException
1889     */
1890    protected String calculateCVVImpl(String accountNo, T cvkA, T cvkB,
1891                                   Date expDate, String serviceCode) throws SMException {
1892        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1893    }
1894
1895
1896    /**
1897     * Your SMAdapter should override this method if it has this functionality
1898     * @param accountNo
1899     * @param cvkA
1900     * @param cvkB
1901     * @param expDate
1902     * @param serviceCode
1903     * @return Card Verification Digit (Code/Value)
1904     * @throws SMException
1905     */
1906    protected String calculateCVDImpl(String accountNo, T cvkA, T cvkB,
1907                                   String expDate, String serviceCode) throws SMException {
1908        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
1909    }
1910
1911
1912    /**
1913     * Your SMAdapter should override this method if it has this functionality
1914     * @param accountNo
1915     * @param cvk
1916     * @param upn
1917     * @param authrc
1918     * @param sfarc
1919     * @return Cardholder Authentication Verification Value
1920     * @throws SMException
1921     */
1922    protected String calculateCAVVImpl(String accountNo, T cvk, String upn,
1923                                    String authrc, String sfarc) throws SMException {
1924        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1925    }
1926
1927    /**
1928     * Your SMAdapter should override this method if it has this functionality
1929     * @param accountNo
1930     * @param cvkA
1931     * @param cvkB
1932     * @param cvv
1933     * @param expDate
1934     * @param serviceCode
1935     * @return true if CVV/CVC is falid or false if not
1936     * @throws SMException
1937     */
1938    protected boolean verifyCVVImpl(String accountNo, T cvkA, T cvkB,
1939                        String cvv, Date expDate, String serviceCode) throws SMException {
1940        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1941    }
1942
1943    /**
1944     * Your SMAdapter should override this method if it has this functionality
1945     * @param accountNo
1946     * @param cvkA
1947     * @param cvkB
1948     * @param cvv
1949     * @param expDate
1950     * @param serviceCode
1951     * @return {@code true} if CVV/CVC is valid or {@code false} otherwise
1952     * @throws SMException
1953     */
1954    protected boolean verifyCVVImpl(String accountNo, T cvkA, T cvkB,
1955                        String cvv, String expDate, String serviceCode) throws SMException {
1956        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
1957    }
1958
1959    /**
1960     * Your SMAdapter should override this method if it has this functionality
1961     * @param accountNo
1962     * @param cvk
1963     * @param cavv
1964     * @param upn
1965     * @param authrc
1966     * @param sfarc
1967     * @return Cardholder Authentication Verification Value
1968     * @throws SMException
1969     */
1970    protected boolean verifyCAVVImpl(String accountNo, T cvk, String cavv,
1971                                     String upn, String authrc, String sfarc) throws SMException {
1972        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1973    }
1974
1975    /**
1976     * Your SMAdapter should override this method if it has this functionality
1977     * @param accountNo
1978     * @param imkac
1979     * @param dcvv
1980     * @param expDate
1981     * @param serviceCode
1982     * @param atc
1983     * @param mkdm
1984     * @return true if dcvv is valid false if not
1985     * @throws SMException
1986     */
1987    protected boolean verifydCVVImpl(String accountNo, T imkac, String dcvv,
1988                     Date expDate, String serviceCode, byte[] atc, MKDMethod mkdm)
1989                     throws SMException {
1990        throw  new SMException("Operation not supported in: " + this.getClass().getName());
1991    }
1992
1993    /**
1994     * Your SMAdapter should override this method if it has this functionality
1995     * @param accountNo
1996     * @param imkac
1997     * @param dcvv
1998     * @param expDate
1999     * @param serviceCode
2000     * @param atc
2001     * @param mkdm
2002     * @return true if dcvv is valid false if not
2003     * @throws SMException
2004     */
2005    protected boolean verifydCVVImpl(String accountNo, T imkac, String dcvv,
2006                     String expDate, String serviceCode, byte[] atc, MKDMethod mkdm)
2007                     throws SMException {
2008        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2009    }
2010
2011    /**
2012     * Your SMAdapter should override this method if it has this functionality
2013     * @param imkcvc3
2014     * @param accountNo
2015     * @param acctSeqNo
2016     * @param atc
2017     * @param upn
2018     * @param data
2019     * @param mkdm
2020     * @param cvc3
2021     * @return true if cvc3 is valid false if not
2022     * @throws SMException
2023     */
2024    protected boolean verifyCVC3Impl(T imkcvc3, String accountNo, String acctSeqNo,
2025                     byte[] atc, byte[] upn, byte[] data, MKDMethod mkdm, String cvc3)
2026                     throws SMException {
2027        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2028    }
2029
2030    /**
2031     * Your SMAdapter should override this method if it has this functionality
2032     * @param mkdm
2033     * @param skdm
2034     * @param imkac
2035     * @param accountNo
2036     * @param acctSeqNo
2037     * @param arqc
2038     * @param atc
2039     * @param upn
2040     * @param txnData
2041     * @return true if ARQC/TC/AAC is valid or false if not
2042     * @throws SMException
2043     */
2044    protected boolean verifyARQCImpl(MKDMethod mkdm, SKDMethod skdm, T imkac
2045            ,String accountNo, String acctSeqNo, byte[] arqc, byte[] atc
2046            ,byte[] upn, byte[] txnData) throws SMException {
2047        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2048    }
2049
2050    /**
2051     * Your SMAdapter should override this method if it has this functionality
2052     * @param mkdm
2053     * @param skdm
2054     * @param imkac
2055     * @param accountNo
2056     * @param acctSeqNo
2057     * @param arqc
2058     * @param atc
2059     * @param upn
2060     * @param arpcMethod
2061     * @param arc
2062     * @param propAuthData
2063     * @return calculated ARPC
2064     * @throws SMException
2065     */
2066    protected byte[] generateARPCImpl(MKDMethod mkdm, SKDMethod skdm, T imkac
2067            ,String accountNo, String acctSeqNo, byte[] arqc, byte[] atc
2068            ,byte[] upn, ARPCMethod arpcMethod, byte[] arc, byte[] propAuthData)
2069            throws SMException {
2070        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2071    }
2072
2073    /**
2074     * Your SMAdapter should override this method if it has this functionality
2075     * @param mkdm
2076     * @param skdm
2077     * @param imkac
2078     * @param accountNo
2079     * @param acctSeqNo
2080     * @param arqc
2081     * @param atc
2082     * @param upn
2083     * @param transData
2084     * @param arpcMethod
2085     * @param arc
2086     * @param propAuthData
2087     * @return calculated ARPC
2088     * @throws SMException
2089     */
2090    protected byte[] verifyARQCGenerateARPCImpl(MKDMethod mkdm, SKDMethod skdm, T imkac
2091            ,String accountNo, String acctSeqNo, byte[] arqc, byte[] atc, byte[] upn
2092            ,byte[] transData, ARPCMethod arpcMethod, byte[] arc, byte[] propAuthData)
2093            throws SMException {
2094        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2095    }
2096
2097
2098
2099    /**
2100     * Your SMAdapter should override this method if it has this functionality
2101     * @param mkdm
2102     * @param skdm
2103     * @param imksmi
2104     * @param accountNo
2105     * @param acctSeqNo
2106     * @param atc
2107     * @param arqc
2108     * @param data
2109     * @return generated 8 bytes MAC
2110     * @throws SMException
2111     */
2112    protected byte[] generateSM_MACImpl(MKDMethod mkdm, SKDMethod skdm
2113            ,T imksmi, String accountNo, String acctSeqNo
2114            ,byte[] atc, byte[] arqc, byte[] data) throws SMException {
2115        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2116    }
2117
2118    /**
2119     * Your SMAdapter should override this method if it has this functionality
2120     * @param mkdm
2121     * @param skdm
2122     * @param padm
2123     * @param imksmi
2124     * @param accountNo
2125     * @param acctSeqNo
2126     * @param atc
2127     * @param arqc
2128     * @param data
2129     * @param currentPIN
2130     * @param newPIN
2131     * @param kd1
2132     * @param imksmc
2133     * @param imkac
2134     * @param destinationPINBlockFormat
2135     * @return Pair of values, encrypted PIN and 8 bytes MAC
2136     * @throws SMException
2137     */
2138    protected Pair<EncryptedPIN,byte[]> translatePINGenerateSM_MACImpl(MKDMethod mkdm
2139           ,SKDMethod skdm, PaddingMethod padm, T imksmi
2140           ,String accountNo, String acctSeqNo, byte[] atc, byte[] arqc
2141           ,byte[] data, EncryptedPIN currentPIN, EncryptedPIN newPIN
2142           ,T kd1, T imksmc, T imkac
2143           ,byte destinationPINBlockFormat) throws SMException {
2144        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2145    }
2146
2147    /**
2148     * Your SMAdapter should override this method if it has this functionality
2149     * @param cipherMode
2150     * @param kd
2151     * @param data
2152     * @param iv
2153     * @return encrypted data
2154     * @throws SMException
2155     */
2156    protected byte[] encryptDataImpl(CipherMode cipherMode, SecureDESKey kd
2157            ,byte[] data, byte[] iv) throws SMException {
2158        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2159    }
2160
2161    /**
2162     * Your SMAdapter should override this method if it has this functionality
2163     * @param cipherMode
2164     * @param kd
2165     * @param data
2166     * @param iv
2167     * @return decrypted data
2168     * @throws SMException
2169     */
2170    protected byte[] decryptDataImpl(CipherMode cipherMode, SecureDESKey kd
2171            ,byte[] data, byte[] iv) throws SMException {
2172        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2173    }
2174
2175    /**
2176     * Your SMAdapter should override this method if it has this functionality
2177     * @param data
2178     * @param kd
2179     * @return generated CBC-MAC
2180     * @throws SMException
2181     */
2182    protected byte[] generateCBC_MACImpl(byte[] data, T kd) throws SMException {
2183        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2184    }
2185
2186    /**
2187     * Your SMAdapter should override this method if it has this functionality
2188     * @param data
2189     * @param kd
2190     * @return generated EDE-MAC
2191     * @throws SMException
2192     */
2193    protected byte[] generateEDE_MACImpl(byte[] data, T kd) throws SMException {
2194        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2195    }
2196
2197    /**
2198     * Translate key from encryption under the LMK held in key change storage
2199     * to encryption under a new LMK.
2200     *
2201     * @param kd the key encrypted under old LMK
2202     * @return key encrypted under the new LMK
2203     * @throws SMException if the parity of the imported key is not adjusted AND checkParity = true
2204     */
2205    protected SecureDESKey translateKeyFromOldLMKImpl(SecureDESKey kd) throws SMException {
2206        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2207    }
2208
2209    /**
2210     * Your SMAdapter should override this method if it has this functionality.
2211     *
2212     * @param key
2213     * @param keySpec
2214     * @return key encrypted under the new LMK
2215     * @throws SMException if the parity of the imported key is not adjusted AND checkParity = true
2216     */
2217    protected SecureKey translateKeyFromOldLMKImpl(SecureKey key, SecureKeySpec keySpec) throws SMException {
2218        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
2219    }
2220
2221    /**
2222     * Your SMAdapter should override this method if it has this functionality
2223     * @param spec algorithm specific parameters (contains e.g. key size)
2224     * @return key pair generated according to passed parameters
2225     * @throws SMException
2226     */
2227    protected Pair<PublicKey, SecurePrivateKey> generateKeyPairImpl(AlgorithmParameterSpec spec)
2228            throws SMException {
2229        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
2230    }
2231
2232    /**
2233     * Your SMAdapter should override this method if it has this functionality.
2234     *
2235     * @param keySpec
2236     * @return key pair generated according to passed parameters
2237     * @throws SMException
2238     */
2239    protected Pair<PublicKey, SecureKey> generateKeyPairImpl(SecureKeySpec keySpec)
2240            throws SMException {
2241        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
2242    }
2243
2244    /**
2245     * Your SMAdapter should override this method if it has this functionality
2246     * @param hash identifier of the hash algorithm used to hash passed data.
2247     * @param privateKey private key used to compute data signature.
2248     * @param data data to be sifned.
2249     * @return signature of passed data.
2250     * @throws SMException
2251     */
2252    protected byte[] calculateSignatureImpl(MessageDigest hash, SecureKey privateKey
2253            ,byte[] data) throws SMException {
2254        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
2255    }
2256
2257    /**
2258     * Encrypts clear Data Block with specified cipher.
2259     *
2260     * @param encKey the data encryption key
2261     * @param data data block to encrypt
2262     * @param algspec algorithm specification
2263     * @param iv the inital vector
2264     * @return encrypted data block
2265     * @throws SMException
2266     */
2267    protected byte[] encryptDataImpl(SecureKey encKey, byte[] data
2268            , AlgorithmParameterSpec algspec, byte[] iv)
2269            throws SMException {
2270        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
2271    }
2272
2273    /**
2274     * Decrypts Data Block encrypted with assymetric cipher.
2275     *
2276     * @param decKey the data decryption key
2277     * @param data data block to decrypt
2278     * @param algspec algorithm specification
2279     * @param iv the inital vector
2280     * @return decrypted data block
2281     * @throws SMException
2282     */
2283    protected byte[] decryptDataImpl(SecureKey decKey, byte[] data
2284            , AlgorithmParameterSpec algspec, byte[] iv)
2285            throws SMException {
2286        throw new UnsupportedOperationException("Operation not supported in: " + this.getClass().getName());
2287    }
2288
2289    /**
2290     * Erase the key change storage area of memory
2291     *
2292     * It is recommended that this command is used after keys stored
2293     * by the Host have been translated from old to new LMKs.
2294     *
2295     * @throws SMException
2296     */
2297    protected void eraseOldLMKImpl () throws SMException {
2298        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2299    }
2300
2301    @Override
2302    public byte[] dataEncrypt(T bdk, byte[] clearText) throws SMException {
2303        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2304    }
2305
2306    @Override
2307    public byte[] dataDecrypt(T bdk, byte[] clearText) throws SMException {
2308        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2309    }
2310
2311    @Override
2312    public SecureDESKey formKEYfromClearComponents(short keyLength, String keyType, String... clearComponents) throws SMException {
2313        throw  new SMException("Operation not supported in: " + this.getClass().getName());
2314    }
2315
2316    private void logEvent(LogEvent evt) {
2317        if (debug)
2318            Logger.log(evt);
2319    }
2320}