Example #1
0
  // ------------------------------------------------
  public final void diversify(byte[] MxK, byte[] factor, byte[] DxK) {
    Util.arrayCopyNonAtomic(factor, (short) 0, tbuf2, (short) 0, (short) 8);

    tripledes(MxK, tbuf2, (short) 0, (short) 8, tbuf1, (short) 0, Cipher.MODE_ENCRYPT);
    Util.arrayCopy(tbuf1, (short) 0, DxK, (short) 0, (short) 8);
    notblock8(tbuf2);
    tripledes(MxK, tbuf2, (short) 0, (short) 8, tbuf1, (short) 0, Cipher.MODE_ENCRYPT);
    Util.arrayCopyNonAtomic(tbuf1, (short) 0, DxK, (short) 8, (short) 8);
  }
  void writeData(short fid, short file_offset, byte[] data, short data_offset, short length) {
    byte[] file = getFile(fid);
    short fileSize = getFileSize(fid);

    if (file == null) {
      ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
    }

    if (fileSize < (short) (file_offset + length)) ISOException.throwIt(ISO7816.SW_FILE_FULL);
    Util.arrayCopyNonAtomic(data, data_offset, file, file_offset, length);
    // Extract the pointers to where the Root and Alternate root CVCA certificate
    // identifiers are stored. Properly this should be done with a BERTLVScanner or
    // similar.
    if (fid == EF_COM_FID) {
      short cvcaRootIndex = -1;
      short cvcaAltIndex = -1;
      for (short i = 0; i < length; i++) {
        if (data[i] == 0x04 && data[(short) (i + 1)] == 0x11) {
          if (cvcaRootIndex == -1) {
            cvcaRootIndex = (short) ((short) (file_offset + i) + 2);
          } else {
            cvcaAltIndex = (short) ((short) (file_offset + i) + 2);
          }
        }
      }
      SmartIDApplet.certificate.setCOMFileData(file, cvcaRootIndex, cvcaAltIndex);
    }
  }
Example #3
0
 /** Process the WRITE BINARY Instruction (0xD0). ISO7816-4 Section 7.2.4 */
 private void processWriteBinary(APDU apdu) throws ISOException {
   if (state != STATE_INITIAL) {
     ISOException.throwIt(SW_INS_NOT_SUPPORTED);
   }
   byte[] buf = apdu.getBuffer();
   byte p1 = buf[OFFSET_P1];
   byte p2 = buf[OFFSET_P2];
   short offset = 0;
   short ef = -1;
   if ((byte) (p1 & MASK_SFI) == MASK_SFI) {
     byte sfi = (byte) (p1 | ~MASK_SFI);
     if (sfi >= 0x1F) {
       ISOException.throwIt(SW_INCORRECT_P1P2);
     }
     ef = fileSystem.findCurrentSFI(sfi);
     if (ef == -1) {
       ISOException.throwIt(SW_FILE_NOT_FOUND);
     }
     ef = fileSystem.fileStructure[ef];
     offset = unsigned(p2);
   } else {
     ef = fileSystem.getCurrentIndex();
     if (fileSystem.getFile(ef) == null) {
       ISOException.throwIt(SW_COMMAND_NOT_ALLOWED);
     }
     offset = Util.makeShort(p1, p2);
   }
   byte[] file = fileSystem.getFile(ef);
   short lc = unsigned(buf[OFFSET_LC]);
   if ((short) (offset + lc) > file.length) {
     ISOException.throwIt(SW_WRONG_LENGTH);
   }
   apdu.setIncomingAndReceive();
   Util.arrayCopyNonAtomic(buf, OFFSET_CDATA, file, offset, lc);
 }
Example #4
0
  /** Process the INTERNAL AUTHENTICATE instruction (0x88) ISO 7816-4 Section 7.5.2 */
  private void processInternalAuthenticate(APDU apdu) {
    if (state != STATE_PERSONALISED) {
      ISOException.throwIt(SW_INS_NOT_SUPPORTED);
    }
    if (!pin.isValidated()) {
      ISOException.throwIt(SW_SECURITY_STATUS_NOT_SATISFIED);
    }
    byte[] buf = apdu.getBuffer();
    short lc = unsigned(buf[OFFSET_LC]);
    if (lc == 0) {
      ISOException.throwIt(SW_WRONG_LENGTH);
    }
    apdu.setIncomingAndReceive();

    RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) currentPrivateKey[0];
    byte alg = tmp[TMP_SIGNALG_OFFSET];
    if (privateKey != authKeyPrivate || alg != ALG_AUTH_DEC_RSA) {
      ISOException.throwIt(SW_WRONG_DATA);
    }
    short offset = OFFSET_CDATA;
    short maxLength = (short) ((short) (privateKey.getSize() / 8) - 11);
    if (lc > maxLength) {
      ISOException.throwIt(SW_WRONG_LENGTH);
    }
    pkcs1Cipher.init(privateKey, Cipher.MODE_ENCRYPT);
    short len = pkcs1Cipher.doFinal(buf, offset, lc, tmp, TMP_OFFSET);
    Util.arrayCopyNonAtomic(tmp, TMP_OFFSET, buf, (short) 0, len);
    apdu.setOutgoingAndSend((short) 0, len);
  }
Example #5
0
  // ------------------------------------------------
  public final void gmac4(byte alg, byte[] key, byte[] data, short dl, byte[] mac) {
    dl = pbocpadding(data, dl);

    Util.arrayFillNonAtomic(tbuf1, (short) 0, (short) 8, (byte) 0);

    for (short i = (short) 0; i < dl; i += (short) 8) {
      xorblock8(tbuf1, data, i);
      cdes(key, (short) 0, tbuf1, (short) 0, (short) 8, tbuf2, (short) 0, Cipher.MODE_ENCRYPT);
      Util.arrayCopyNonAtomic(tbuf2, (short) 0, tbuf1, (short) 0, (short) 8);
    }

    if (alg == ALG_3DES) {
      cdes(key, (short) 8, tbuf1, (short) 0, (short) 8, tbuf2, (short) 0, Cipher.MODE_DECRYPT);
      cdes(key, (short) 0, tbuf2, (short) 0, (short) 8, tbuf1, (short) 0, Cipher.MODE_ENCRYPT);
    }

    Util.arrayCopyNonAtomic(tbuf1, (short) 0, mac, (short) 0, (short) 4);
  }
Example #6
0
  // ------------------------------------------------
  public final short PBDecrypt(
      byte alg, byte[] key, byte[] data, short doff, short len, byte[] res) {
    if (alg == ALG_3DES) tripledes(key, data, doff, len, res, (short) 0, Cipher.MODE_DECRYPT);
    else cdes(key, (short) 0, data, doff, len, res, (short) 0, Cipher.MODE_DECRYPT);

    len = res[0];
    Util.arrayCopyNonAtomic(res, (short) 1, res, (short) 0, len);
    return len;
  }
Example #7
0
  // ------------------------------------------------
  public final short PBEncrypt(byte alg, byte[] key, byte[] data, short len, byte[] res) {
    Util.arrayCopyNonAtomic(data, (short) 0, res, (short) 1, len);
    res[0] = (byte) len;

    if (((short) (len + 1) % (short) 8) > (short) 0) len = pbocpadding(res, (short) (len + 1));
    else len = (short) (len + 1);

    if (alg == ALG_3DES) {
      tripledes(key, data, (short) 0, len, res, (short) 0, Cipher.MODE_ENCRYPT);
    } else {
      cdes(key, (short) 0, data, (short) 0, len, res, (short) 0, Cipher.MODE_ENCRYPT);
    }

    return len;
  }
Example #8
0
  /** Process the PSO COMPUTE DIGITAL SIGNATURE instruction (0x2A) ISO 7816-8 Section 5.4 */
  private void processComputeDigitalSignature(APDU apdu) {
    pin.reset();
    byte[] buf = apdu.getBuffer();
    short lc = unsigned(buf[OFFSET_LC]);
    if (lc == 0) {
      ISOException.throwIt(SW_WRONG_LENGTH);
    }
    apdu.setIncomingAndReceive();

    RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) currentPrivateKey[0];
    byte alg = tmp[TMP_SIGNALG_OFFSET];
    if (privateKey != signKeyPrivate
        || (alg != ALG_SIGN_RSA_PKCS1_SHA1
            && alg != ALG_SIGN_RSA_PKCS1_SHA256
            && alg != ALG_SIGN_RSA_PSS
            && alg != ALG_SIGN_RSA_PKCS1_SHA1MD5)) {
      ISOException.throwIt(SW_WRONG_DATA);
    }
    short offset = OFFSET_CDATA;
    short expectedLength = 0;
    if (alg == ALG_SIGN_RSA_PKCS1_SHA256) {
      expectedLength = (short) (SHA256_LEN + 17);
    } else if (alg == ALG_SIGN_RSA_PKCS1_SHA1) {
      expectedLength = (short) (SHA1_LEN + 13);
    } else if (alg == ALG_SIGN_RSA_PSS) {
      expectedLength = SHA1_LEN;
    } else if (alg == ALG_SIGN_RSA_PKCS1_SHA1MD5) {
      expectedLength = SHA1MD5_LEN;
    }
    if (lc != expectedLength) {
      ISOException.throwIt(SW_WRONG_LENGTH);
    }
    short sigLen = 0;
    if (alg == ALG_SIGN_RSA_PKCS1_SHA1
        || alg == ALG_SIGN_RSA_PKCS1_SHA256
        || alg == ALG_SIGN_RSA_PKCS1_SHA1MD5) {
      pkcs1Cipher.init(privateKey, Cipher.MODE_ENCRYPT);
      sigLen = pkcs1Cipher.doFinal(buf, offset, lc, tmp, TMP_OFFSET);
      Util.arrayCopyNonAtomic(tmp, TMP_OFFSET, buf, (short) 0, sigLen);
    } else {
      short emLen = (short) (privateKey.getSize() / 8);
      pssPad(buf, offset, lc, tmp, TMP_OFFSET, emLen, signKeyFirstModulusByte);
      nopadCipher.init(privateKey, Cipher.MODE_ENCRYPT);
      sigLen = nopadCipher.doFinal(tmp, (short) 0, emLen, buf, (short) 0);
    }
    apdu.setOutgoingAndSend((short) 0, sigLen);
  }
Example #9
0
  /**
   * Pads the input according to the RSASSA-PSS algorithm, the result is placed in output. The input
   * should be 20-byte SHA1 hash of the message to be signed. This method *does not* do signing
   * (encrypting) itself. Due to the randomness of this algorithm the subsequent signing may fail
   * (when the result of this method is larger than the key modulus) in which case the padding
   * should be attempted again.
   */
  private void pssPad(
      byte[] input,
      short inOffset,
      short hashLen,
      byte[] output,
      short outputOffset,
      short emLen,
      byte firstKeyByte)
      throws CryptoException {
    do {
      short hLen = hashLen;
      short outOffset = outputOffset;
      if (hLen != SHA1_LEN
          || (short) (inOffset + hLen) > input.length
          || (short) (outOffset + emLen) > output.length) {
        CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
      }
      short sLen = SHA1_LEN;
      short psLen = (short) (emLen - sLen - hLen - 2);
      Util.arrayFillNonAtomic(output, outOffset, emLen, (byte) 0x00);
      md.update(output, outOffset, (short) 8);
      md.update(input, inOffset, hLen);
      rd.generateData(output, (short) (outOffset + psLen + 1), sLen);
      md.doFinal(output, (short) (outOffset + psLen + 1), sLen, tmp, TMP_HASH_OFFSET);

      output[(short) (outOffset + psLen)] = (byte) 0x01;
      Util.arrayFillNonAtomic(output, outOffset, psLen, (byte) 0x00);

      short hOffset = (short) (outOffset + emLen - hLen - 1);
      Util.arrayCopyNonAtomic(tmp, TMP_HASH_OFFSET, output, hOffset, hLen);
      output[(short) (outOffset + emLen - 1)] = (byte) 0xbc;
      tmp[(short) (TMP_C_OFFSET + C_LEN - 1)] = 0;
      while (outOffset < hOffset) {
        md.update(output, hOffset, hLen);
        md.doFinal(tmp, TMP_C_OFFSET, C_LEN, tmp, TMP_HASH_OFFSET);
        if ((short) (outOffset + hLen) > hOffset) {
          hLen = (short) (hOffset - outOffset);
        }
        for (short i = 0; i < hLen; i++) {
          output[outOffset++] ^= tmp[(short) (TMP_HASH_OFFSET + i)];
        }
        tmp[(short) (TMP_C_OFFSET + C_LEN - 1)]++;
      }
    } while (firstKeyByte <= tmp[TMP_OFFSET]);
  }
  /**
   * Processes an incoming APDU.
   *
   * @see APDU
   * @param apdu the incoming APDU
   * @exception ISOException with the response bytes per ISO 7816-4
   */
  public void process(APDU apdu) {
    byte buffer[] = apdu.getBuffer();

    short bytesRead = apdu.setIncomingAndReceive();
    short echoOffset = (short) 0;

    while (bytesRead > 0) {
      Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, echoBytes, echoOffset, bytesRead);
      echoOffset += bytesRead;
      bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
    }

    apdu.setOutgoing();
    apdu.setOutgoingLength((short) (echoOffset + 5));

    // echo header
    apdu.sendBytes((short) 0, (short) 5);
    // echo data
    apdu.sendBytesLong(echoBytes, (short) 0, echoOffset);
  }
Example #11
0
  /** Process the PSO DECIPHER instruction. ISO 7816-8 Section 5.10 */
  private void processDecipher(APDU apdu) {
    byte[] buf = apdu.getBuffer();
    byte cla = buf[OFFSET_CLA];
    boolean chain = ((byte) (cla & CLA_CHAIN) == CLA_CHAIN);
    short lc = unsigned(buf[OFFSET_LC]);

    // We need at least 1 byte of data to feed into the cipher,
    // so that a progression is made
    if (lc == 0) {
      ISOException.throwIt(SW_WRONG_LENGTH);
    }
    apdu.setIncomingAndReceive();
    short offset = OFFSET_CDATA;

    // The first in chain, intialized and check:
    if (tmp[TMP_DECSEQ_OFFSET] == (byte) 0x00) {
      RSAPrivateCrtKey key = (RSAPrivateCrtKey) currentPrivateKey[0];
      if (key == null) {
        ISOException.throwIt(SW_KEY_NOT_FOUND);
      }
      byte alg = tmp[TMP_SIGNALG_OFFSET];
      if (key != decKeyPrivate || alg != ALG_AUTH_DEC_RSA) {
        ISOException.throwIt(SW_WRONG_DATA);
      }
      pkcs1Cipher.init(key, Cipher.MODE_DECRYPT);
      tmp[TMP_DECSEQ_OFFSET]++;
      expectedDecipherDataLength[0] = (short) (key.getSize() / 8);
    }

    short decipheredLen = 0;
    try {
      decipheredLen =
          pkcs1Cipher.update(buf, offset, lc, tmp, (short) (TMP_OFFSET + decipheredLen));
    } catch (CryptoException ce) {
      ISOException.throwIt(SW_WRONG_DATA);
    }
    expectedDecipherDataLength[0] -= lc;
    offset += lc;

    // Data still to come:
    if (expectedDecipherDataLength[0] != 0 && !chain) {
      ISOException.throwIt(SW_WRONG_DATA);
    }
    // No more data:
    if (expectedDecipherDataLength[0] == 0 && chain) {
      ISOException.throwIt(SW_LAST_COMMAND_EXPECTED);
    }

    if (chain) {
      // It should also be the case the deciphereLen == 0, check?
      return;
    }
    pin.reset();
    tmp[TMP_DECSEQ_OFFSET] = 0x00;
    try {
      decipheredLen =
          pkcs1Cipher.doFinal(buf, offset, (short) 0, tmp, (short) (TMP_OFFSET + decipheredLen));
    } catch (CryptoException ce) {
      ISOException.throwIt(SW_WRONG_DATA);
    }
    Util.arrayCopyNonAtomic(tmp, TMP_OFFSET, buf, (short) 0, decipheredLen);
    apdu.setOutgoingAndSend((short) 0, decipheredLen);
  }
Example #12
0
 public void setSeed(byte[] buffer, short offset, short length) {
   byte[] seed = new byte[length];
   Util.arrayCopyNonAtomic(buffer, offset, seed, (short) 0, length);
   engine.addSeedMaterial(seed);
 }