Генерация MAC на основе ISO 9797 Alg3 из открытого текста - PullRequest
0 голосов
/ 04 ноября 2019

Мне нужно сгенерировать MAC на основе ISO 9797 Alg3 из открытого текста. Я уже написал ту же функцию в Java и C # с помощью инструмента "BouncyCastle" очень просто, как следующий код. Но в интернете нет примеров для python.

using System.Text;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Macs;
using System.Security.Cryptography;
using System.IO;

namespace TestGenerateMAC2
{
    class Program
    {
        public static string getMac(string text, string key)
        {
            byte[] keyBytes = StringToByteArray(key);
            byte[] data = Encoding.UTF8.GetBytes(text);
            DesEngine cipher = new DesEngine();
            ISO9797Alg3Mac mac = new ISO9797Alg3Mac(cipher);

            KeyParameter keyP = new KeyParameter(keyBytes);
            mac.Init(keyP);
            mac.BlockUpdate(data, 0, data.Length);

            byte[] outPut = new byte[8];

            mac.DoFinal(outPut, 0);

            return BytesToHex(outPut);
        }
        public static byte[] StringToByteArray(string hex)
        {
            return Enumerable.Range(0, hex.Length)
                             .Where(x => x % 2 == 0)
                             .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                             .ToArray();
        }

        public static string BytesToHex(byte[] bytes)
        {
            return String.Concat(Array.ConvertAll(bytes, delegate (byte x) { return x.ToString("X2"); })).ToLower();
        }

  }
}

Существует ли такой же пример для python?

Ответы [ 2 ]

0 голосов
/ 11 ноября 2019

Спасибо, Мартен!

Я нашел и изменил код на основе вашего описания. Следующий код решил мою проблему.

Большое спасибо

import sys
from Crypto.Cipher import DES
from Crypto.Cipher import DES3
from Crypto.Util.strxor import strxor
import binascii


def macIso9797_m2_alg3(key, msg):
    return macIso9797_alg3(key, msg, "80")

def macIso9797_m1_alg3(key, msg):
    return macIso9797_alg3(key, msg, "00")

def macIso9797_alg3(key, msg, pad_start):

    key_len = int(len(key)/2)    

    if (key_len != 16):
        raise ValueError("Key length should be 16 digits")    

    # force header  padding
    msg += pad_start

    # padding with "00"
    lenRestOfData = int((len(msg)/2) % 8)
    msg += "00"*(8-lenRestOfData)

    loopNum = int((len(msg)/2) / 8)

    bufferOutput = binascii.unhexlify("00"*8)
    IV = '\x00'*8    

    keya = binascii.unhexlify(key[0:16])
    keyb = binascii.unhexlify(key[16:])

    i = 0
    for i in range (0, loopNum):
        tdesa = DES.new(keya, DES.MODE_ECB)

        data = msg[i*16:i*16+16]

        x = bufferOutput
        bufferOutput = strxor(binascii.unhexlify(data), bufferOutput)

        bufferOutput = tdesa.encrypt(bufferOutput)

    tdesb = DES.new(keyb, DES.MODE_ECB)
    bufferOutput = tdesb.decrypt(bufferOutput)

    tdesa = DES.new(keya, DES.MODE_ECB)
    bufferOutput = tdesa.encrypt(bufferOutput)

    return bufferOutput


macKey="mac key"
message="text message"

hexMessage = bytes(message, encoding='utf-8').hex()

print('MAC Key: ' + macKey)
print('MAC: ' + macIso9797_m1_alg3(macKey, hexMessage).hex())
0 голосов
/ 04 ноября 2019

Запрос примеров явно не по теме, но я покажу, как вы можете создать алгоритм в целом , используя шифры DES CBC и DES ECB.

Все операции включеныбайты или байтовые массивы.

  1. разделить 16-байтовый ключ на ключ A и ключ B
  2. init DES CBC-шифрование с ключом A и нулевым IV в 8 байтов
  3. перебирать все полные блоки в сообщении и для каждого блока выполнять шифрование CBC, отбрасывая результат (используя тот же экземпляр шифра, вам нужно сохранить состояние в конце концов)
  4. создать последний блок ископируйте оставшиеся байты сообщения в него
  5. в следующей позиции, добавьте начальный байт индикатора заполнения
  6. , завершите шифрование CBC, зашифровав последний блок, и сохраните результат
  7. выполнить дешифрование DES ECB по результату с помощью ключа B, заменив результат
  8. , выполнить шифрование DES ECB по результату с помощью ключа A, заменив результат

Изатем, конечно, верните результат.

... счастливое программирование


Ну, так как ответ был принят, я воздержусь от предупреждения не публиковать пример кода и публиковать свой собственныйпросто для того, чтобы продемонстрировать хорошие методы программирования (насколько я могу создавать те, у кого есть моё понимание Python):

import sys
from Crypto.Cipher import DES
from Crypto.Cipher import DES3
from Crypto.Util.strxor import strxor
import binascii

def macIso9797_m1_alg3(key, msg):
    return macIso9797_alg3(key, msg, b"\x00")

def macIso9797_m2_alg3(key, msg):
    return macIso9797_alg3(key, msg, b"\x80")

def macIso9797_alg3(key, msg, pad_start):
    if (len(key) != 16):
        raise ValueError("Key length should be 16 bytes")

    keya = key[:8]
    keyb = key[8:]

    full_blocks = len(msg) / 8

    # b"\x00" * 8 might be slightly faster
    desa = DES.new(keya, DES.MODE_CBC, bytes(bytearray(8)))
    for i in range(0, full_blocks):
        off = i * 8
        block = msg[off:off + 8]
        # don't need the ciphertext, just the internal state
        desa.encrypt(block)

    # create padded final block
    final_block = bytearray(8)
    left = len(msg) % 8
    final_block[0:left] = msg[-left:]

    final_block[left] = pad_start

    res = desa.encrypt(bytes(final_block))

    # cipher may not *just* return the final block (but does)
    if (len(res) > 8):
        res = res[-8:]    

    desb = DES.new(keyb, DES.MODE_ECB)
    res = desb.decrypt(res)

    desc = DES.new(keya, DES.MODE_ECB)
    res = desc.encrypt(res)

    return res

macKey="EA1302AFBCCF791CB0065BFAD948B092"
message="test message"

res = macIso9797_m1_alg3(binascii.unhexlify(macKey), message)

print("MAC key: " + binascii.hexlify(res))

Обратите внимание, что документация API объектов DES / cipher в приведенном выше коде неясно, какие данные возвращаются и когда. Поэтому я вставил оператор if для извлечения последнего блока зашифрованного текста, который явно не нужен при реализации current . Это, вероятно, слишком осторожно (но это относится к криптодомену).

Также обратите внимание, что я создал последний блок для заполнения за пределами самого сообщения. Заполнение самого сообщения опасно (вы можете использовать это сообщение для других целей) и / или ресурсоемко, поскольку копирование большого сообщения - плохая идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...