Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Расчет MAC по ANSI X9.19  [new]
rvsn
Member

Откуда:
Сообщений: 8
Добрый день!

Столкнулся с необходимостью рассчитать МАС по стандарту ANSI X9.19. Полного описания нагуглить не смог,
базировался на Описание на английском и Описание на русском.
Попробовал воспроизвести с использованием пакетов dbms_obfuscation_toolkit и DBMS_CRYPTO. К сожалению, разультат расчета не совпадает с контрольным просчетом.
Публиковать исходное сообщение и ключ не имею права.
Версия Enterprise Edition Release 11.2.0.2.0 - 64bit Production.
Буду признателен за подсказку, что я неправильно делаю.
+ Мои попытки:

/*=====По описанию с http://www.academia.edu/5336984/ANSI_X9_24-2004_info =======*/
  FUNCTION GetMac(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_type         PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES +
                                   DBMS_CRYPTO.CHAIN_CBC +
                                   DBMS_CRYPTO.PAD_NONE;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
                
    FOR i IN 0 .. LENGTH(vi_package) / 16 - 1
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      vi_result := utl_raw.bit_xor(vi_result, vi_buffer);
      vi_result := DBMS_CRYPTO.Encrypt(vi_result, vi_type, vi_LeftHalfKey);
    END LOOP;
    vi_result := DBMS_CRYPTO.Decrypt(vi_result, vi_type, vi_RightHalfKey);
    vi_result := DBMS_CRYPTO.Encrypt(vi_result, vi_type, vi_LeftHalfKey);
    RETURN utl_raw.substr(vi_result, 1, 4);
  END;
  /*======= По описанию с http://www.aliveinternet.ru/post136825028 =======*/
  FUNCTION GetMac1(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_count        INTEGER;
    vi_type         PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES +
                                   DBMS_CRYPTO.CHAIN_CBC +
                                   DBMS_CRYPTO.PAD_NONE;
    vi_type1        PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_3DES_2KEY +
                                   DBMS_CRYPTO.CHAIN_CBC +
                                   DBMS_CRYPTO.PAD_NONE;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
    vi_count   := LENGTH(vi_package) / 16 - 1;                      
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      
      vi_result := utl_raw.bit_xor(vi_result, vi_buffer);
      IF i != vi_count THEN
        vi_result := DBMS_CRYPTO.Encrypt(vi_result, vi_type, vi_LeftHalfKey);
      ELSE
        vi_result := DBMS_CRYPTO.Encrypt(vi_result, vi_type1, pi_key);
      END IF;
    END LOOP;
    RETURN utl_raw.substr(vi_result, 1, 4);
  END;  
  /*======= По описанию с http://www.aliveinternet.ru/post136825028 с указанием вектора инициализации без xor =======*/
  FUNCTION GetMac2(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_count        INTEGER;
    vi_type         PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES +
                                   DBMS_CRYPTO.CHAIN_CBC +
                                   DBMS_CRYPTO.PAD_NONE;
    vi_type1        PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_3DES_2KEY +
                                   DBMS_CRYPTO.CHAIN_CBC +
                                   DBMS_CRYPTO.PAD_NONE;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
    vi_count   := LENGTH(vi_package) / 16 - 1;                      
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      IF i != vi_count THEN
        vi_result := DBMS_CRYPTO.Encrypt(vi_buffer, vi_type, vi_LeftHalfKey, vi_result);
      ELSE
        vi_result := DBMS_CRYPTO.Encrypt(vi_buffer, vi_type1, pi_key, vi_result);
      END IF;
    END LOOP;
    RETURN utl_raw.substr(vi_result, 1, 4);
  END;  
  /*=====По описанию с http://www.academia.edu/5336984/ANSI_X9_24-2004_info с указанием вектора инициализации без xor =======*/
  FUNCTION GetMac3(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_type         PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES +
                                   DBMS_CRYPTO.CHAIN_CBC +
                                   DBMS_CRYPTO.PAD_NONE;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
    FOR i IN 0 .. LENGTH(vi_package) / 16 - 1
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      vi_result := DBMS_CRYPTO.Encrypt(vi_buffer, vi_type, vi_LeftHalfKey,vi_result);
    END LOOP;
    vi_result := DBMS_CRYPTO.Decrypt(vi_result, vi_type, vi_RightHalfKey);
    vi_result := DBMS_CRYPTO.Encrypt(vi_result, vi_type, vi_LeftHalfKey);
    RETURN utl_raw.substr(vi_result, 1, 4);
  END; 
  /*=====По описанию с http://www.aliveinternet.ru/post136825028 dbms_obfuscation_toolkit =======*/    
  FUNCTION GetMac4(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_count        INTEGER;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
    vi_count   := LENGTH(vi_package) / 16 - 1;                     
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      vi_result := utl_raw.bit_xor(vi_result, vi_buffer);      
      IF i != vi_count THEN
        vi_result := dbms_obfuscation_toolkit.DESEncrypt(input => vi_buffer,key => vi_LeftHalfKey);
      ELSE
        vi_result := dbms_obfuscation_toolkit.DES3Encrypt(input => vi_buffer,key => pi_key);
      END IF;
    END LOOP;
    RETURN utl_raw.substr(vi_result, 1, 4);
  END; 
  /*=====По описанию с http://www.aliveinternet.ru/post136825028 dbms_obfuscation_toolkit с вектором инициализации =======*/    
  FUNCTION GetMac5(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_count        INTEGER;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
    vi_count   := LENGTH(vi_package) / 16 - 1;                     
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      IF i != vi_count THEN
        vi_result := utl_raw.bit_xor(vi_result, vi_buffer); 
        vi_result := dbms_obfuscation_toolkit.DESEncrypt(input => vi_buffer,key => vi_LeftHalfKey);
      ELSE
        vi_result := dbms_obfuscation_toolkit.DES3Encrypt(input => vi_buffer,key => pi_key,iv => vi_result);
      END IF;
    END LOOP;
    RETURN utl_raw.substr(vi_result, 1, 4);
  END;   
  /*=====По описанию с http://www.academia.edu/5336984/ANSI_X9_24-2004_info dbms_obfuscation_toolkit =======*/
  FUNCTION GetMac6(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_count        INTEGER;
  BEGIN
    vi_package := rpad(pi_source,
                       LENGTH(pi_source) + (16 - MOD(LENGTH(pi_source), 16)),
                       '0');
    vi_count   := LENGTH(vi_package) / 16 - 1;                     
    FOR i IN 0 .. LENGTH(vi_package) / 16 - 1
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      vi_result := utl_raw.bit_xor(vi_result, vi_buffer);
      vi_result := dbms_obfuscation_toolkit.DESEncrypt(input => vi_buffer,key => vi_LeftHalfKey);
    END LOOP;
    vi_result := dbms_obfuscation_toolkit.DESDecrypt(input => vi_buffer,key => vi_RightHalfKey);
    vi_result := dbms_obfuscation_toolkit.DESEncrypt(input => vi_buffer,key => vi_LeftHalfKey);
    RETURN utl_raw.substr(vi_result, 1, 4);    
  END; 

28 авг 14, 11:42    [16505847]     Ответить | Цитировать Сообщить модератору
 Re: Расчет MAC по ANSI X9.19  [new]
MazoHist
Guest
Не понял, зачем самому извращаться с дополнением до нужной длины, если есть замечательная константа sys.DBMS_CRYPTO.PAD_ZERO ? В итоге у меня получилось следующее:
+

  FUNCTION GetMac7(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_count        INTEGER;
    vi_type         PLS_INTEGER := sys.DBMS_CRYPTO.ENCRYPT_DES +
                                   sys.DBMS_CRYPTO.CHAIN_CBC +
                                   sys.DBMS_CRYPTO.PAD_ZERO;
    vi_type1        PLS_INTEGER := sys.DBMS_CRYPTO.ENCRYPT_3DES_2KEY +
                                   sys.DBMS_CRYPTO.CHAIN_CBC +
                                   sys.DBMS_CRYPTO.PAD_ZERO;
  BEGIN
    vi_count := ceil(LENGTH(pi_source) / 16) - 1;
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := hextoraw(substr(pi_source, (i * 16) + 1, 16));
      vi_result := utl_raw.bit_xor(vi_result, vi_buffer);
      IF i != vi_count THEN
        vi_result := sys.DBMS_CRYPTO.Encrypt(vi_result, vi_type, vi_LeftHalfKey);
      ELSE
        vi_result := sys.DBMS_CRYPTO.Encrypt(vi_result, vi_type1, pi_key);
      END IF;
    END LOOP;
    RETURN vi_result; --utl_raw.substr(vi_result, 1, 4);
    
  END;  


Отделять первую половину не стал - сверял с результатом этой тулзы - совпадает.
Исходный вариант тоже совпадает, если правильно дополнять:
+

  
FUNCTION GetMac1(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 0, 8);
    vi_RightHalfKey RAW(8) := utl_raw.substr(pi_key, 9);
    vi_result       RAW(8) := hextoraw('0000000000000000');
    vi_buffer       RAW(8);
    vi_package      VARCHAR2(32000);
    vi_count        INTEGER;
    vi_type         PLS_INTEGER := sys.DBMS_CRYPTO.ENCRYPT_DES +
                                   sys.DBMS_CRYPTO.CHAIN_CBC +
                                   sys.DBMS_CRYPTO.PAD_NONE;
    vi_type1        PLS_INTEGER := sys.DBMS_CRYPTO.ENCRYPT_3DES_2KEY +
                                   sys.DBMS_CRYPTO.CHAIN_CBC +
                                   sys.DBMS_CRYPTO.PAD_NONE;
  BEGIN
    vi_package := rpad(pi_source,  16 * ceil(LENGTH(pi_source)/ 16) ,'0'); 
    vi_count   := LENGTH(vi_package) / 16 - 1;
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := hextoraw(substr(vi_package, (i * 16) + 1, 16));
      
      vi_result := utl_raw.bit_xor(vi_result, vi_buffer);
      IF i != vi_count THEN
        vi_result := sys.DBMS_CRYPTO.Encrypt(vi_result, vi_type, vi_LeftHalfKey);
      ELSE
        vi_result := sys.DBMS_CRYPTO.Encrypt(vi_result, vi_type1, pi_key);
      END IF;
    END LOOP;
    RETURN vi_result; --utl_raw.substr(vi_result, 1, 4);
  END;  

28 авг 14, 13:54    [16506897]     Ответить | Цитировать Сообщить модератору
 Re: Расчет MAC по ANSI X9.19  [new]
rvsn
Member

Откуда:
Сообщений: 8
MazoHist,

Спасибо за отклик.
Ваше замечание про дополнение до нужной длины справедливо, но к сожалению на моих данных результат расчета отличается от контрольного
(совпадает с ранее полученными результатами функций GetMac, GetMac1, GetMac2,GetMac3).
Попробую завтра у себя уточнить по корректности предоставленного ключа.
28 авг 14, 14:22    [16507082]     Ответить | Цитировать Сообщить модератору
 Re: Расчет MAC по ANSI X9.19  [new]
rvsn
Member

Откуда:
Сообщений: 8
Если кому будет интересно, то вариант, предоставленный MazoHist, вполне работоспособный.
+ Мой вариант - финал

 /*Расчет MAC*/  
 FUNCTION GetMac(pi_source IN VARCHAR2, pi_key IN RAW) RETURN RAW IS
    vi_LeftHalfKey  RAW(8) := utl_raw.substr(pi_key, 1, 8);
    vi_result       RAW(8) := '0000000000000000';
    vi_buffer       RAW(8);
    vi_count        INTEGER;
    vi_type         PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_DES +
                                   DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_ZERO;
    vi_type1        PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_3DES_2KEY + 
                                   DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_ZERO;
  BEGIN
    vi_count := ceil(LENGTH(pi_source) / 16) - 1;
    FOR i IN 0 .. vi_count
    LOOP
      vi_buffer := substr(pi_source, (i * 16) + 1, 16);
      IF i != vi_count THEN
        vi_result := DBMS_CRYPTO.Encrypt(vi_buffer, vi_type, vi_LeftHalfKey, vi_result);
      ELSE
        vi_result := DBMS_CRYPTO.Encrypt(vi_buffer, vi_type1, pi_key, vi_result);
      END IF;
    END LOOP;
    RETURN utl_raw.substr(vi_result, 1, 4);
  END; 

9 окт 14, 15:57    [16682692]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить