【问题标题】:Calculate CVV from Credit card tracks?从信用卡轨迹计算 CVV?
【发布时间】:2016-03-31 02:17:36
【问题描述】:

我可以从 3 信用卡跟踪数据计算 CVV 吗? 当我扫描一张卡片时,没有 CVV,只有与其他任何东西无关的号码、姓名和服务号码。

参考:Parse Credit Card input from Magnetic Stripe

【问题讨论】:

  • 这在某种程度上是 CVV 的重点:它不在磁条中。

标签: credit-card


【解决方案1】:

您需要两个 DES 密钥(CVK)、卡号、服务代码、有效期来生成 CVV。

CVV = Fun(CVK1, CVK2, card_no, service_code, expiry_YYMM);

共有三个 CVV

CVV1:在磁条中 CVV2 : 卡片背面 ICVD:在芯片数据中

每个 CVV 的服务代码不同

CVV1 的服务代码:根据卡类型和用途而有所不同 CVV2 的服务代码:000 ICVD 服务代码:999*

我已经实现了以下 CVV 生成算法

 private static final char[] decTable = "0123456789012345".toCharArray();

    private static final int hexToByte(char ch) {
        if ('0' <= ch && ch <= '9') return ch - '0';
        if ('A' <= ch && ch <= 'F') return ch - 'A' + 10;
        if ('a' <= ch && ch <= 'f') return ch - 'a' + 10;
        return -1;
    }

    /**
     * @param cvk1      : card verification key1
     * @param cvk2      : card verification key1
     * @param pan       : Account No
     * @param svc       : Service code CVV1(000), ICVV(999), CVV2(custom)
     * @param expiry    : Expiry date in YYMM format
     * @return          : CVV
     */
    public static final String calculateCVV(final String cvk1, final String cvk2, final String pan, final String svc, final String expiry) {
        String input = Strings.padRight(new StringBuilder().append(pan).append(expiry).append(svc), '0', 32);
        String data1 = input.substring(0, 16);
        String data2 = input.substring(16);
        String d1 = DES.encrypt(data1, cvk1, null, MODE.ECB, PADDING.NoPadding);
        String d2 = ByteHexUtil.byteToHex(ByteHexUtil.xor(ByteHexUtil.hexToByte(d1), ByteHexUtil.hexToByte(data2)));
        String d3 = TripleDES.encrypt(d2, cvk1 + cvk2, null, MODE.ECB, PADDING.NoPadding);
        return Decimalizer.decimalizeDigitsFirst(d3, 3);
    }

//该方法以一个加密的值(十六进制字符串)作为输入, 扫描数字 [0-9] 并选择它们以形成 cvv。如果没有 输入十六进制字符串中的数字小于它开始的 outLen 从头开始扫描(不包括先前选择的数字)并转换 使用十进制表将十六进制[A-F]字符转换为数字。

    public static final String decimalizeDigitsFirst(String data, final int outLen) {
        StringBuilder selected = new StringBuilder(outLen);
        int selectionCounter = 0;
        int len = data.length();
        for(int i=0; i<len && selectionCounter < outLen ; i++){
            if(hexToByte(data.charAt(i)) < 10) {
                selected.append(data.charAt(i));
                selectionCounter++;
            }
        }
        if(selectionCounter !=2) {
            for(int i=0; i<len && selectionCounter < outLen ; i++){
                if(hexToByte(data.charAt(i)) > 9) {
                    selected.append(decTable[hexToByte(data.charAt(i))]);
                    selectionCounter++;
                }
            }
        }
        return selected.toString();
    }

测试向量

String CVK1 = "F40157F249232FCE";
String CVK2 = "7CE6C8CB9E8683EC";
String EXP_YYMM = "2005";
String SVC = "520";
String PAN = "4263970000005262";
String CVV = calculateCVV(CVK1, CVK2, PAN, SVC, EXP_YYMM);
EXPECTED CVV OUTPUT : 782

上述函数的输出与具有相同数据的 Thales 9000 HSM 的输出相匹配。使用上面提到的十进制表。

【讨论】:

  • selected.append(decTable[hexToByte(data.charAt(i))]);中的decTable是什么?
  • @koding 十进制表的主要目的是将十六进制字符值映射到一些十进制字符值。我已经用我们通常使用的样本十进制表更新了答案。发卡机构也可以使用十进制表来随机化 CVV。
  • 感谢兄弟分享
  • @koding 我已经为 decimalizeDigitsFirst 方法添加了上下文。通过将其输出与 Thales PayShield 9000 HSM 输出与一小组测试向量进行比较,该实现被测试正常。我打算用不同的十进制表和大量的测试向量来测试它。一旦有结果,我会在这里告诉你结果。
  • @koding 还添加了缺少的 hexToByte 方法。
【解决方案2】:

磁条上的 CVV 实际上是一个 CVC1 代码,它只是试图验证磁条细节没有被篡改/损坏。它与印在卡片背面的 CVV 代码(正式称为 CVC2 代码)不同,也没有任何关系。

印在卡片背面的 CVC2(按设计)仅供肉眼查看,机器无法读取。

更多阅读:https://randomoracle.wordpress.com/2012/08/25/cvv1-cvv2-cvv3-demystifying-credit-card-data-12/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 2014-05-22
    • 1970-01-01
    相关资源
    最近更新 更多