CAPDU build_CA_Step_C(const std::vector<unsigned char>& Puk_IFD_DH) { GeneralAuthenticate authenticate = GeneralAuthenticate( GeneralAuthenticate::P1_NO_INFO, GeneralAuthenticate::P2_NO_INFO); authenticate.setNe(CAPDU::DATA_SHORT_MAX); std::vector<unsigned char> puk; puk.push_back(0x04); puk.insert(puk.end(), Puk_IFD_DH.begin(), Puk_IFD_DH.end()); authenticate.setData(TLV_encode(0x7C, TLV_encode(0x80, puk))); return authenticate; }
CAPDU build_CA_Step_C(const std::vector<unsigned char>& Puk_IFD_DH) { GeneralAuthenticate authenticate = GeneralAuthenticate( GeneralAuthenticate::P1_NO_INFO, GeneralAuthenticate::P2_NO_INFO); authenticate.setNe(CAPDU::DATA_SHORT_MAX); std::vector<unsigned char> puk; //The server sends the public ephemeral key already with 0x04 //prefix. So we do not need to prepend it anymore. //puk.push_back(0x04); puk.insert(puk.end(), Puk_IFD_DH.begin(), Puk_IFD_DH.end()); authenticate.setData(TLV_encode(0x7C, TLV_encode(0x80, puk))); return authenticate; }
static std::vector<unsigned char> buildDO87_AES( const std::vector<unsigned char>& kEnc, const std::vector<unsigned char>& data, unsigned long long ssc) { std::vector<unsigned char> data_ = static_cast<std::vector<unsigned char> >(data); data_.push_back(0x80); while (data_.size() % kEnc.size()) data_.push_back(0x00); unsigned char iv_[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; std::vector<unsigned char> ssc_; for (int i = 0; i < 8; i++) ssc_.push_back(0x00); ssc_.push_back((ssc << 56) & 0xFF); ssc_.push_back((ssc << 48) & 0xFF); ssc_.push_back((ssc << 40) & 0xFF); ssc_.push_back((ssc << 32) & 0xFF); ssc_.push_back((ssc << 24) & 0xFF); ssc_.push_back((ssc << 16) & 0xFF); ssc_.push_back((ssc << 8) & 0xFF); ssc_.push_back(ssc & 0xFF); Integer issc(ssc_.data(), kEnc.size()); std::vector<unsigned char> vssc; vssc.resize(kEnc.size()); issc.Encode(vssc.data(), kEnc.size()); std::vector<unsigned char> calculatedIV_; CBC_Mode<AES>::Encryption AESCBC_encryption; if (false == AESCBC_encryption.IsValidKeyLength(kEnc.size())) return calculatedIV_; calculatedIV_.resize(kEnc.size()); AESCBC_encryption.SetKeyWithIV(kEnc.data(), kEnc.size(), iv_); AESCBC_encryption.ProcessData(calculatedIV_.data(), vssc.data(), vssc.size()); CBC_Mode<AES>::Encryption AESCBC_encryption1; std::vector<unsigned char> encryptedData_; encryptedData_.resize(data_.size()); AESCBC_encryption1.SetKeyWithIV(kEnc.data(), kEnc.size(), calculatedIV_.data()); AESCBC_encryption1.ProcessData(encryptedData_.data(), data_.data(), data_.size()); // Append padding content indicator encryptedData_.insert(encryptedData_.begin(), BIT_PADDING); return TLV_encode(0x87, encryptedData_); }
CAPDU build_CA_Step_B(const OBJECT_IDENTIFIER_t& CA_OID, const unsigned char sessionid) { MSE mse = MSE(MSE::P1_SET | MSE::P1_COMPUTE, MSE::P2_AT); // Build up command data field std::vector<unsigned char> oid(CA_OID.buf, CA_OID.buf+CA_OID.size);; std::vector<unsigned char> data = TLV_encode(0x80, oid); if (sessionid) { data.push_back(0xE0); data.push_back(0x03); data.push_back(0x81); data.push_back(0x01); data.push_back(sessionid); } mse.setData(data); return mse; }
CAPDU ePACard::applySM(const CAPDU &capdu) { std::vector<unsigned char> do87_, do8E_, do97_, Le, sm_data; debug_CAPDU("Unencrypted", capdu); CAPDU sm_apdu = CAPDU(capdu.getCLA() | CAPDU::CLA_SM, capdu.getINS(), capdu.getP1(), capdu.getP2()); m_ssc++; if (!capdu.getData().empty()) { do87_ = buildDO87_AES(m_kEnc, capdu.getData(), m_ssc); } Le = capdu.encodedLe(); if (!Le.empty()) { if (Le.size() > 2) { Le.erase(Le.begin()); } do97_ = TLV_encode(0x97, Le); } /* here, sm_apdu is still a case 1 APDU with header only. */ do8E_ = buildDO8E_AES(m_kMac, sm_apdu.asBuffer(), do87_, do97_, m_ssc); sm_data = do87_; sm_data.insert(sm_data.end(), do97_.begin(), do97_.end()); sm_data.insert(sm_data.end(), do8E_.begin(), do8E_.end()); sm_apdu.setData(sm_data); if (sm_apdu.isExtended() || capdu.isExtended()) sm_apdu.setNe(CAPDU::DATA_EXTENDED_MAX); else sm_apdu.setNe(CAPDU::DATA_SHORT_MAX); return sm_apdu; }
static std::vector<unsigned char> buildDO8E_AES( const std::vector<unsigned char>& kMac, const std::vector<unsigned char>& data, const std::vector<unsigned char>& do87, const std::vector<unsigned char>& do97, unsigned long long &ssc) { std::vector<unsigned char> mac; mac.resize(8); std::vector<unsigned char> data_ = static_cast<std::vector<unsigned char> >(data); // Do padding on APDU header data_.push_back(0x80); while (data_.size() % AES::BLOCKSIZE) data_.push_back(0x00); // Append the DO87 data for (size_t u = 0; u < do87.size(); u++) data_.push_back(do87[u]); // Append the DO97 data for (size_t u = 0; u < do97.size(); u++) data_.push_back(do97[u]); // Append padding to data part if (!do97.empty() || !do87.empty()) { data_.push_back(0x80); while (data_.size() % AES::BLOCKSIZE) data_.push_back(0x00); } std::vector<unsigned char> ssc_; for (int i = 0; i < 8; i++) ssc_.push_back(0x00); ssc_.push_back((ssc << 56) & 0xFF); ssc_.push_back((ssc << 48) & 0xFF); ssc_.push_back((ssc << 40) & 0xFF); ssc_.push_back((ssc << 32) & 0xFF); ssc_.push_back((ssc << 24) & 0xFF); ssc_.push_back((ssc << 16) & 0xFF); ssc_.push_back((ssc << 8) & 0xFF); ssc_.push_back(ssc & 0xFF); Integer issc(ssc_.data(), AES::BLOCKSIZE); std::vector<unsigned char> vssc; vssc.resize(AES::BLOCKSIZE); issc.Encode(vssc.data(), AES::BLOCKSIZE); issc.Encode(ssc_.data(), AES::BLOCKSIZE); ssc = 0; ssc += (unsigned long long) ssc_[8] << 56; ssc += (unsigned long long) ssc_[9] << 48; ssc += (unsigned long long) ssc_[10] << 40; ssc += (unsigned long long) ssc_[11] << 32; ssc += (unsigned long long) ssc_[12] << 24; ssc += (unsigned long long) ssc_[13] << 16; ssc += (unsigned long long) ssc_[14] << 8; ssc += (unsigned long long) ssc_[15]; for (size_t t = 0; t < data_.size(); t++) vssc.push_back(data_[t]); std::vector<unsigned char> result_; result_.resize(vssc.size()); CMAC<AES> cmac; cmac.SetKey(kMac.data(), kMac.size()); cmac.Update(vssc.data(), vssc.size()); cmac.Final(result_.data()); result_.resize(8); return TLV_encode(0x8E, result_); }