14#include "keyple/card/calypso/CommandIncreaseOrDecreaseMultiple.hpp"
22#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
23#include "keyple/card/calypso/CalypsoCardClass.hpp"
24#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
25#include "keyple/card/calypso/CardCommandRef.hpp"
26#include "keyple/card/calypso/CardDataAccessException.hpp"
27#include "keyple/card/calypso/CardDataOutOfBoundsException.hpp"
28#include "keyple/card/calypso/CardIllegalParameterException.hpp"
29#include "keyple/card/calypso/CardSecurityContextException.hpp"
30#include "keyple/card/calypso/CardSessionBufferOverflowException.hpp"
31#include "keyple/core/util/ApduUtil.hpp"
32#include "keyple/core/util/ByteArrayUtil.hpp"
33#include "keyple/core/util/HexUtil.hpp"
34#include "keyple/core/util/cpp/Arrays.hpp"
35#include "keyple/core/util/cpp/MapUtils.hpp"
36#include "keyple/core/util/cpp/System.hpp"
37#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
43using keyple::core::util::ApduUtil;
44using keyple::core::util::ByteArrayUtil;
45using keyple::core::util::HexUtil;
46using keyple::core::util::cpp::Arrays;
47using keyple::core::util::cpp::MapUtils;
48using keyple::core::util::cpp::System;
49using keyple::core::util::cpp::exception::IllegalStateException;
51const std::map<int, const std::shared_ptr<Command::StatusProperties>>
52 CommandIncreaseOrDecreaseMultiple::STATUS_TABLE = [] {
53 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
54 Command::STATUS_TABLE);
58 std::make_shared<Command::StatusProperties>(
59 "Too many modifications in session",
60 typeid(CardSessionBufferOverflowException))},
62 std::make_shared<Command::StatusProperties>(
63 "Lc value not supported",
typeid(CardDataAccessException))},
65 std::make_shared<Command::StatusProperties>(
66 "The current EF is not a Counters or Simulated Counter EF",
67 typeid(CardDataAccessException))},
69 std::make_shared<Command::StatusProperties>(
70 "Security conditions not fulfilled (no secure session, "
71 "incorrect key, encryption required, PKI mode and not Always "
73 typeid(CardSecurityContextException))},
75 std::make_shared<Command::StatusProperties>(
76 "Access forbidden (Never access mode, DF is invalidated, "
78 typeid(CardAccessForbiddenException))},
80 std::make_shared<Command::StatusProperties>(
81 "Incorrect file type: the Current File is not an EF. "
83 typeid(CardDataAccessException))},
85 std::make_shared<Command::StatusProperties>(
86 "Incorrect command data (Overflow error, Incorrect counter "
87 "number, Counter number present more than once)",
88 typeid(CardIllegalParameterException))},
90 std::make_shared<Command::StatusProperties>(
91 "File not found",
typeid(CardDataAccessException))},
93 std::make_shared<Command::StatusProperties>(
94 "P1 or P2 value not supported",
95 typeid(CardIllegalParameterException))}});
99CommandIncreaseOrDecreaseMultiple::CommandIncreaseOrDecreaseMultiple(
100 bool isDecreaseCommand,
101 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
103 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
105 const std::map<int, int>& counterNumberToIncDecValueMap)
107 isDecreaseCommand ? CardCommandRef::DECREASE_MULTIPLE
108 : CardCommandRef::INCREASE_MULTIPLE,
109 std::unique_ptr<int>(
110 new int(static_cast<int>(counterNumberToIncDecValueMap.size()) * 4)),
114, mCounterNumberToIncDecValueMap(counterNumberToIncDecValueMap)
116 const std::uint8_t p1 = 0;
117 const std::uint8_t p2 = (sfi * 8);
118 std::vector<std::uint8_t> dataIn(4 * counterNumberToIncDecValueMap.size());
121 for (
const auto& entry : counterNumberToIncDecValueMap) {
122 dataIn[index] =
static_cast<std::uint8_t
>(entry.first);
123 int incDecValue = entry.second;
124 ByteArrayUtil::copyBytes(incDecValue, dataIn, index + 1, 3);
130 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
131 transactionContext->getCard()->getCardClass().getValue(),
132 getCommandRef().getInstructionByte(),
138 std::stringstream extraInfo;
139 extraInfo <<
"SFI:" << HexUtil::toHex(sfi);
140 for (
const auto& entry : counterNumberToIncDecValueMap) {
142 extraInfo << entry.first <<
": " << entry.second;
145 addSubName(extraInfo.str());
149CommandIncreaseOrDecreaseMultiple::finalizeRequest()
151 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
155CommandIncreaseOrDecreaseMultiple::isCryptoServiceRequiredToFinalizeRequest()
158 return getCommandContext()->isEncryptionActive();
162CommandIncreaseOrDecreaseMultiple ::
163 synchronizeCryptoServiceBeforeCardProcessing()
165 if (getCommandContext()->isEncryptionActive()) {
169 updateTerminalSessionIfNeeded(buildAnticipatedResponse());
175CommandIncreaseOrDecreaseMultiple::parseResponse(
176 std::shared_ptr<ApduResponseApi> apduResponse)
178 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
179 Command::setApduResponseAndCheckStatus(apduResponse);
181 if (apduResponse->getDataOut().size() > 0) {
182 const std::vector<std::uint8_t> dataOut = apduResponse->getDataOut();
183 int nbCounters =
static_cast<int>(dataOut.size()) / 4;
184 for (
int i = 0; i < nbCounters; i++) {
185 getTransactionContext()->getCard()->setCounter(
187 dataOut[i * 4] & 0xFF,
188 Arrays::copyOfRange(dataOut, (i * 4) + 1, (i * 4) + 4));
192 updateTerminalSessionIfNeeded();
195const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
196CommandIncreaseOrDecreaseMultiple::getStatusTable()
const
201std::vector<std::uint8_t>
202CommandIncreaseOrDecreaseMultiple::buildAnticipatedResponse()
205 std::map<const int, const int> oldCounterValues = getOldCounterValues();
206 std::vector<std::uint8_t> response(
207 2 + (mCounterNumberToIncDecValueMap.size() * 4));
210 for (
const auto& entry : mCounterNumberToIncDecValueMap) {
211 response[index] =
static_cast<std::uint8_t
>(entry.first);
214 if (getCommandRef() == CardCommandRef::DECREASE_MULTIPLE) {
215 newCounterValue = oldCounterValues[entry.first] - entry.second;
217 newCounterValue = oldCounterValues[entry.first] + entry.second;
220 ByteArrayUtil::copyBytes(newCounterValue, response, index + 1, 3);
225 response[index] = 0x90;
226 response[index + 1] = 0x00;
231std::map<const int, const int>
232CommandIncreaseOrDecreaseMultiple::getOldCounterValues()
234 std::shared_ptr<ElementaryFile> ef
235 = getTransactionContext()->getCard()->getFileBySfi(mSfi);
238 const std::map<const int, const int> allCountersValue
239 = ef->getData()->getAllCountersValue();
241 const std::vector<int> allCountersValueKeySet
242 = MapUtils::getKeySet(allCountersValue);
243 const std::vector<int> counterNumberToIncDecValueKeySet
244 = MapUtils::getKeySet(mCounterNumberToIncDecValueMap);
246 if (Arrays::containsAll(
247 allCountersValueKeySet, counterNumberToIncDecValueKeySet)) {
248 return allCountersValue;
252 throw new IllegalStateException(
253 std::string(
"Unable to determine anticipated APDU response ")
254 +
"because some expected counters have not been read beforehand. "
255 +
"Command: " + getName() +
", SFI: " + HexUtil::toHex(mSfi) +
"h");