4

私の会社は、カードリーダーを現場に置くプロジェクトに取り組んでいます。リーダーは DUKPT TripleDES 暗号化を使用するため、サーバー上のカード データを復号化するソフトウェアを開発する必要があります。

私はこの問題の表面をなぞり始めたばかりですが、一見単純な問題に行き詰まっていることに気付きます... IPEK を生成しようとしている (対称鍵を再作成するための最初のステップ)。

IPEK は、2 つのトリプル DES で暗号化された 8 バイトの 16 進文字列を連結して作成された 16 バイトの 16 進値です。

パディングの有無にかかわらず、ECB および CBC (IV のゼロ) モードを試しましたが、入力と同じサイズの結果が必要な場合、個々のエンコーディングの結果は常に 16 バイト以上 (2 ブロック以上) になります。実際、このプロセス全体を通して、暗号文はエンコードされる平文と同じサイズである必要があります。

<cfset x = encrypt("FFFF9876543210E0",binaryEncode(binaryDecode("0123456789ABCDEFFEDCBA98765432100123456789ABCDEF", "hex"), "base64") ,"DESEDE/CBC/PKCS5Padding","hex",BinaryDecode("0000000000000000","hex"))>

結果: 3C65DEC44CC216A686B2481BECE788D197F730A72D4A8CDD

NoPadding フラグを使用すると、結果は次のようになります。

3C65DEC44CC216A686B2481BECE788D1

また、平文の16進メッセージをbase64としてエンコードしようとしました(キーがそうであるように)。上記の例では、次の結果が返されます。

DE5BCC68EB1B2E14CEC35EB22AF04EFC。

NoPadding フラグを使用する以外は同じことを行うと、「入力長が 8 バイトの倍数ではありません」というエラーが表示されます。

私は暗号化に慣れていないので、ここで非常に基本的なエラーを犯していることを願っています。これらのブロック暗号アルゴリズムによって生成された暗号文が平文メッセージと同じ長さでないのはなぜですか?

もう少し背景を知るために、「それを実行する」演習として、ここで説明されている作業を複製しようとしました。

https://www.parthenonsoftware.com/blog/how-to-decrypt-magnetic-stripe-scanner-data-with-dukpt/

4

2 に答える 2

2

それが関連しているかどうかはわかりませんし、あなたが探している答えではないかもしれませんが、バグ ID 3842326のテストに時間を費やしました。異なる属性を使用する場合、CF はフードの下でシードとソルトを異なる方法で処理しています。たとえば、定数 (関数呼び出しでハードコードされた文字列) ではなく変数を暗号化する文字列として渡すと、結果の文字列は毎回変化します。それはおそらく異なるメソッド署名を示しています.1つのフラグと別のフラグを使用した例では、似たようなものを見ています.

どちらの場合も結果の文字列が暗号化されていない可能性があることを考えると、これは実際にはバグではなく、注意すべき動作です。結果の文字列を暗号化できますか?

于 2014-12-09T19:07:51.400 に答える
1

問題はencrypt()、入力が UTF-8 文字列であると予想されることです。したがって、16 進数としてデコードされたときの文字列のではなく、実際にはリテラル文字 FFFF-9.... を暗号化しています。

代わりに、16 進文字列をバイナリにデコードしてから、encryptBinary()関数を使用する必要があります。(リンクに記載されていないことに注意ivしてください。したがって、CBC ではなく ECB モードを使用していると思います。) 関数はバイナリも返すbinaryEncodeため、結果をより使いやすい 16 進文字列に変換するために使用します。

編集: ECB + "NoPadding" に切り替えると、望ましい結果が得られます。

ksnInHex = "FFFF9876543210E0";
bdkInHex = "0123456789ABCDEFFEDCBA98765432100123456789ABCDEF";
ksnBytes = binaryDecode(ksnInHex, "hex");
bdkBase64 = binaryEncode(binaryDecode(bdkInHex, "hex"), "base64");
bytes = encryptBinary(ksnBytes, bdkBase64, "DESEDE/ECB/NoPadding");
leftRegister = binaryEncode(bytes, "hex");

...生成するもの:

6AC292FAA1315B4D 

これを行うには、元の 16 バイトの BDK から始めたいと思います...そして、次のマスクで XOR します....

残念ながら、ほとんどの CF 数学関数は 32 ビット整数に制限されています。したがって、ネイティブ CF 関数だけを使用して次のステップを実行することはおそらくできません。1 つのオプションは、Java のBigIntegerクラスを使用することです。16 進文字列から大きな整数を作成し、xor()メソッドを使用してマスクを適用します。最後に、toString(radix)メソッドを使用して結果を 16 進文字列として返します。

bdkText ="0123456789ABCDEFFEDCBA9876543210";
maskText = "C0C0C0C000000000C0C0C0C000000000";

// use radix=16 to create integers from the hex strings
bdk = createObject("java", "java.math.BigInteger").init(bdkText, 16);
mask = createObject("java", "java.math.BigInteger").init(maskText, 16);
// apply the mask and convert the result to hex (upper case)
newKeyHex = ucase( bdk.xor(mask).toString(16) );
WriteOutput("<br>newKey="& newKeyHex);
writeOutput("<br>expected=C1E385A789ABCDEF3E1C7A5876543210");

それはあなたを軌道に戻すのに十分なはずです。ここでの CF の制限のいくつかを考えると、Java の方が IMO に適しています。慣れている場合は、小さな Java クラスを作成して、代わりに CF から呼び出すことができます。

于 2014-12-09T20:08:01.433 に答える