Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник
Коллекция курьезных вопросов из форумов
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.org

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

Алгоритм контрольной суммы Флетчера


cryptologic ©   (24.03.21 16:47

Попытался реализовать  на Delphi алгоритм функции контроля четности Флетчера
Читал https://ru.wikipedia.org/wiki/Контрольная_сумма_Флетчера
Но, что то не до конца все понял, сделал на столько сколько понял, если кому интересно присоединяйтесь позаморачиваемся.

unit Fletcher;

(************************************************************************* ******
 Implementation of agorhythm "Fletcher"
 Autor by SUPERBOT
 Source Linck https://en.wikipedia.org/wiki/Fletcher%27s_checksum
 Source Linck https://ru.wikipedia.org/wiki/Контрольная_сумма_Флетчера
*******************************************************************************)

interface
uses SysUtils;
   
function Fletcher16(AStrData: AnsiString): UInt16;
function Fletcher32(AStrData: AnsiString): UInt32;
function Fletcher64(AStrData: AnsiString): UInt64;

implementation
{---------------------------------- Fletcher16 --------------------------------}
function Fletcher16(AStrData: AnsiString): UInt16;
var
 sum1, sum2 : UInt16;
 ch: AnsiChar;
begin
 sum1 := 0;
 sum2 := 0;
 for ch in AStrData do
 begin
   sum1 := (sum1 + Byte(ch)) mod $ff;
   sum2 := (sum2 + sum1) mod $ff;
 end;
 Result := (sum2 shl 8) or sum1;
end;

{-------------------------------- Fletcher32 ----------------------------------}
function Fletcher32(AStrData: AnsiString): UInt32;
var
 sum1, sum2: UInt32;
 ch: AnsiChar;
begin
 sum1 := 0;
 sum2 := 0;
 for ch in AStrData do
 begin
   sum1 := (sum1 + Byte(ch)) mod $ffff;
   sum2 := (sum2 + sum2) mod $ffff;
 end;
 Result := (sum2 shl 16) or sum1;
end;

{------------------------ Fletcher64 -----------------------}
function Fletcher64(AStrData: AnsiString): UInt64;
var
 sum1, sum2: UInt64;
 ch: AnsiChar;
begin
 sum1 := 0;
 sum2 := 0;
 for ch in AStrData do
 begin
   sum1 := (sum1 + Byte(ch)) mod $ffff;
   sum2 := (sum2 + sum1) mod $ffff;
 end;
 Result := (sum2 shl 16) or sum1;
end;

end.


manaka ©   (24.03.21 17:07[1]


> Попытался реализовать  на Delphi алгоритм функции контроля
> четности Флетчера

А он разве не реализован? :(


manaka ©   (24.03.21 17:09[2]


> А он разве не реализован? :(


> Читал https://ru.wikipedia.org/wiki/Контрольная_сумма_Флетчера

Там даже примеры кода есть.

> если кому интересно присоединяйтесь позаморачиваемся.

зачем?


cryptologic ©   (24.03.21 17:12[3]


> manaka ©   (24.03.21 17:07) [1]
>


Где он реализован?


cryptologic ©   (24.03.21 17:14[4]


> manaka ©   (24.03.21 17:09) [2]


Если тебе не зачем, что пишешь сюда?


manaka ©   (24.03.21 17:16[5]


> Если тебе не зачем, что пишешь сюда?

А что, запрещено декретом Совнаркома, что ли?

> Где он реализован?

В Гугле забанили?
писала же:

> Там даже примеры кода есть.


cryptologic ©   (24.03.21 17:21[6]

У меня сомнения вызывают функции Fletcher32 и Fletcher64
какая подача байт должна быть в sum1 по 1 байту или блоками по 4 байта (Fletcher32) байта или блоками по 8 байт в (Fletcher64)


> manaka ©   (24.03.21 17:09) [2]
>

что касается примеров, то это только пример 16 битной функции


cryptologic ©   (24.03.21 17:22[7]


> manaka ©   (24.03.21 17:16) [5]


Много ты там найдешь?


manaka ©   (24.03.21 17:22[8]


>
> что касается примеров, то это только пример 16 битной функции

вроде 32 тоже есть


manaka ©   (24.03.21 17:24[9]


> manaka ©   (24.03.21 17:09) [2]
> > если кому интересно присоединяйтесь позаморачиваемся.
> зачем?

Нормальный, на мой взгляд, вопрос программиста.
Действительно, а зачем?


manaka ©   (24.03.21 17:29[10]

Тем более, в [0] непонятно, а что не так в ВАШЕМ коде?


manaka ©   (24.03.21 17:48[11]


> У меня сомнения вызывают функции Fletcher32 и Fletcher64
> какая подача байт должна быть в sum1 по 1 байту или блоками
> по 4 байта (Fletcher32) байта или блоками по 8 байт в (Fletcher64)

А что нам говорит теория подсчета контрольной суммы Флетчера?


cryptologic ©   (24.03.21 17:50[12]


> manaka ©   (24.03.21 17:29) [10]
> Тем более, в [0] непонятно, а что не так в ВАШЕМ коде?
>
>

Хотя бы потому что элементарная ошибка в функции Fletcher64...
Теперь она выглядит так:

{------------------------ Fletcher64 -----------------------}
function Fletcher64(AStrData: AnsiString): UInt64;
var
 sum1, sum2: UInt64;
 ch: AnsiChar;
begin
 sum1 := 0;
 sum2 := 0;
 for ch in AStrData do
 begin
   sum1 := (sum1 + Byte(ch)) mod $FFFFFFFF;
   sum2 := (sum2 + sum1) mod $FFFFFFFF;
 end;
 Result := (sum2 shl 32) or sum1;
end;


manaka ©   (24.03.21 17:51[13]


> {-------------------------------- Fletcher32 -----------
> -----------------------}
> function Fletcher32(AStrData: AnsiString): UInt32;
> var
>  sum1, sum2: UInt32;
>  ch: AnsiChar;
> begin
>  sum1 := 0;
>  sum2 := 0;
>  for ch in AStrData do
>  begin
>    sum1 := (sum1 + Byte(ch)) mod $ffff;
>    sum2 := (sum2 + sum2) mod $ffff;
>  end;
>  Result := (sum2 shl 16) or sum1;
> end;
>
> {------------------------ Fletcher64 -------------------
> ----}
> function Fletcher64(AStrData: AnsiString): UInt64;
> var
>  sum1, sum2: UInt64;
>  ch: AnsiChar;
> begin
>  sum1 := 0;
>  sum2 := 0;
>  for ch in AStrData do
>  begin
>    sum1 := (sum1 + Byte(ch)) mod $ffff;
>    sum2 := (sum2 + sum1) mod $ffff;
>  end;
>  Result := (sum2 shl 16) or sum1;
> end;

Найдите два различия? Я не нашла... (((


manaka ©   (24.03.21 17:52[14]


> Хотя бы потому что элементарная ошибка в функции Fletcher64.
> ..
> Теперь она выглядит так:

Ошибка то в чем?


manaka ©   (24.03.21 17:53[15]

Что то я сегодня "не в контакте".
Завтра перечитаю, постараюсь понять.


cryptologic ©   (24.03.21 18:04[16]


> manaka ©   (24.03.21 17:29) [10]


Если тебе так все дается легко и без проблем конвертируй мне этот код на delphi я даже тысячу руб. готов заплатить

"""
Python implementation of the COMP128 (aka A3A8) algorithm version 2 and 3
Author: Tamas Jos (@skelsec)
Email:  info [at] skelsec.com
"""
table0=[197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203, 61,
 126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33, 160,
 184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46, 113,
 187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222, 137,
 233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231, 54,
 209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30, 2,
 155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112, 56,
 173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175, 67,
 128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145, 138,
 7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169, 213,
 88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86, 226,
 141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242, 206,
 97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251, 29,
 216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204, 43,
 247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250, 139,
 19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26 ]

table1=[170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129, 216,
 79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235, 6,
 20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18, 224,
 171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178, 156,
 52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222, 76,
 139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138, 31,
 56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154, 179,
 131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245, 193,
 78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169, 68,
 101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59, 21,
 92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82, 54,
 237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207, 181,
 29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148, 209,
 98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80, 196,
 33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149, 226,
 218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112]

def comp128v23_internal(KXOR,RAND):
"""Internal part of the COMP128v23 algo, should not be called manually
"""
temp = [0] * 16
KM_RM = RAND + KXOR

for i in range(5):
 for z in range(16):
  temp[z] = table0[table1[KM_RM[16+z]] ^ KM_RM[z] ]

 j = 0
 while ( (1 << i) > j):
  k = 0
  while ( (1 << (4 - i)) > k ):
   KM_RM[((2 * k + 1) << i )+j] = table0[table1[temp[(k << i) + j]] ^ (KM_RM[(k << i) + 16 + j])]
   KM_RM[ (k << (i + 1)) + j] = temp[(k << i) + j]
   k = k+1
  j = j + 1
 
output = [0]*16

for i in range(16):
 for j in range(8):
  output[i] = output[i] ^ (((KM_RM[(19 * (j + 8 * i) + 19) % 256 / 8] >> (3 * j + 3) % 8) & 1) << j)

return output

def comp128v23(K, RAND, version = 2):
"""The entry point for COMP128v2 and COMP128v3 algorithm
K = The secret Ki number (that should be inside of your SIM card) - Format: list of integers
RAND = The random number generated by the tower - Format: list of integers
version = Version selecting integer (can be 2 or 3) - Format: integer
"""

assert version in [2,3] , "This function only support COMP128 version 2 and 3!"
assert len(K) == 16     , "Ki incorrect (length must be 16)"
assert len(RAND) == 16  , "RAND incorrect (length must be 16)"

K_MIX = [0]*16
RAND_MIX = [0]*16
KATYVASZ = [0]*16
output = [0]*16

for i in range(8):
 K_MIX[i] = K[15 - i]
 K_MIX[15 - i] = K[i]

for i in range(8):
 RAND_MIX[i] = RAND[15 - i]
 RAND_MIX[15 - i] = RAND[i]

for i in range(16):
 KATYVASZ[i] = K_MIX[i] ^ RAND_MIX[i]

for i in range(8):
 RAND_MIX = comp128v23_internal(KATYVASZ,RAND_MIX)

for i in range(16):
 output[i] = RAND_MIX[15-i]


if version == 2:
 output[15] = 0
 output[14] = 4 * (output[14] >> 2)

s = 8
i = 0
while i < 4:
 output[s+i-4] = output[s+i]
 output[s+i] = output[s+i+4]
 i = i+1

#the algorithm uses 16 bytes until this point, but only 12 bytes are effective
#also 12 bytes coming out from the SIM card

output_final = output[:12]
return output_final


def hex2intarr(input):
"""converts hex string to an array of integers
"""
return map(lambda a: int(a.encode('hex'),16), (a for a in input.decode('hex')))
 
def intarr2hex(input):
"""converts array of integers to hex strings
"""
return ''.join('{:02x}'.format(x) for x in input).upper()

if __name__ == '__main__':
import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('Ki', metavar='Ki', default = "00000000000000000000000000000000" ,nargs='?', help='The super secret Ki key')
   #parser.add_argument('Ki', metavar='Ki', default = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ,nargs='?', help='The super secret Ki key')
parser.add_argument('RAND', metavar='RAND', default = "00000000000000000000000000000000", nargs='?', help='The RANDom number you recieve from the tower')
   # parser.add_argument('RAND', metavar='RAND', default = "6E6989BE6CEE7154543770AE80B1EF0D", nargs='?', help='The RANDom number you recieve from the tower')
parser.add_argument('version', metavar='version', default = 3, nargs='?', help='The version of the COMP128 algo you wish to use (options: 2 or 3)')

args = parser.parse_args()

Ki = hex2intarr(args.Ki)
RAND = hex2intarr(args.RAND)
version = args.version

print '----------- INPUT  -------------'
print 'COMP128 version ' + str(version)
print 'Ki:      ' + intarr2hex(Ki)
print 'RAND:    ' + intarr2hex(RAND)

OUTPUT = comp128v23(Ki, RAND, version)
SRES = OUTPUT[:4]
Kc = OUTPUT[4:]

print '----------- OUTPUT -------------'
print "SIM OUTPUT:" + intarr2hex(OUTPUT)
print "SRES:  " + intarr2hex(SRES)
print "Kc:    " + intarr2hex(Kc)


cryptologic ©   (24.03.21 18:12[17]


> cryptologic ©   (24.03.21 18:04) [16]
>

Это тот же код для поста cryptologic ©   (24.03.21 18:04) [16]  но другая его реализация только на СИ или С++  так, что бы понятнее было из двух исходников один сконвертировать,  

manaka © - если ты так во всем очень сильно разбираешься то транслируй код на Delphi, я вознаграждение кину


/*! \file comp128v23.c
* COMP128 version 2 and 3 implementation, common algorithm used for GSM Authentication (A3/A8).
*
* This code is a C conversion of the original code by Tamas Jos <info@skelsec.com> from:
* - original (out of service): http://www.hackingprojects.net/
* - original (archive): https://web.archive.org/web/20130730113347/http://www.hackingprojects.net/
* - new site: https://github.com/skelsec/COMP128
*/
/*
* (C) 2013 by Kévin Redon <kevredon@mail.tsaitgaist.info>
*
* All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

#include <stdint.h>
#include <string.h>

/*! \addtogroup auth
*  @{
* \file comp128v23.c */

static const uint8_t table0[256] = {
197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203, 61,
126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33, 160,
184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46, 113,
187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222, 137,
233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231, 54,
209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30, 2,
155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112, 56,
173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175, 67,
128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145, 138,
7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169, 213,
88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86, 226,
141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242, 206,
97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251, 29,
216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204, 43,
247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250, 139,
19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26
}, table1[256] = {
170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129, 216,
79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235, 6,
20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18, 224,
171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178, 156,
52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222, 76,
139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138, 31,
56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154, 179,
131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245, 193,
78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169, 68,
101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59, 21,
92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82, 54,
237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207, 181,
29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148, 209,
98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80, 196,
33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149, 226,
218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112
};

static void
_comp128v23_internal(uint8_t *output, const uint8_t *kxor, const uint8_t *rand)
{
uint8_t temp[16];
uint8_t km_rm[32];
uint8_t i,j,k,z;

memset(temp, 0, sizeof(temp));
memcpy(km_rm, rand, 16);
memcpy(km_rm + 16, kxor, 16);

for (i=0; i<5; i++) {
 for (z=0; z<16; z++) {
  temp[z] = table0[table1[km_rm[16+z]]^km_rm[z]];
 }
 j=0;
 while ((1<<i)>j) {
  k = 0;
  while ((1<<(4-i))>k) {
   km_rm[((2*k+1)<<i)+j] = table0[table1[temp[(k<<i)+j]]^(km_rm[(k<<i)+16+j])];
   km_rm[(k<<(i+1))+j] = temp[(k<<i)+j];
   k++;
  }
  j++;
 }
}

memset(output,0,16);

for (i=0; i<16; i++) {
 for (j=0; j<8; j++) {
  output[i] ^= (((km_rm[(19*(j+8*i)+19)%256/8]>>(3*j+3)%8)&1)<< j);
 }
}
}

/*! Perform COMP128v3 algorithm
*  \param[in] ki Secret Key K(i) of subscriber
*  \param[in] rand Random Challenge
*  \param[out] sres user-supplied buffer for storing computed SRES value
*  \param[out] kc user-supplied buffer for storing computed Kc value
*  \returns 0 */
int
comp128v3(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc)
{
uint8_t k_mix[16];
uint8_t rand_mix[16];
uint8_t katyvasz[16];
uint8_t output[16];
uint8_t i;

memset(k_mix, 0, sizeof(k_mix));
memset(rand_mix, 0, sizeof(rand_mix));
memset(katyvasz, 0, sizeof(katyvasz));
memset(output, 0, sizeof(output));

for (i=0; i<8; i++) {
 k_mix[i] = ki[15 - i];
 k_mix[15 - i] = ki[i];
}

for (i=0; i<8; i++) {
 rand_mix[i] = rand[15 - i];
 rand_mix[15 - i] = rand[i];
}

for (i=0; i<16; i++) {
 katyvasz[i] = k_mix[i]^rand_mix[i];
}

for (i=0; i<8; i++) {
 _comp128v23_internal(rand_mix,katyvasz,rand_mix);
}

for (i=0; i<16; i++) {
 output[i] = rand_mix[15-i];
}

memmove(output + 4, output + 8, 8); /* ignore bytes 4..7 */

/* the algorithm uses 16 bytes until this point, but only 12 bytes are effective
 * also 12 bytes coming out from the SIM card */
memcpy(sres, output, 4);
memcpy(kc, output + 4, 8);

return 0;
}

/*! Perform COMP128v2 algorithm
*  \param[in] ki Secret Key K(i) of subscriber
*  \param[in] rand Random Challenge
*  \param[out] sres user-supplied buffer for storing computed SRES value
*  \param[out] kc user-supplied buffer for storing computed Kc value
*  \returns 0 */
int
comp128v2(const uint8_t *ki, const uint8_t *rand, uint8_t *sres, uint8_t *kc)
{
int r = comp128v3(ki, rand, sres, kc);
kc[7] = 0; /* 10 last bits of Kc forced to 0 */
kc[6] &= 0xfc;
return r;
}


Rouse_ ©   (24.03.21 21:15[18]

А зачем это тебе если ты простейший сишный исходник на дельфю конвернуть не можешь?

Ну на, делов на 5 минут с перекуром.

program comp128v23;

{$APPTYPE CONSOLE}

{$R *.res}

uses
 Windows,
 System.SysUtils;

const
 table0: array [0..255] of Byte = (
   197, 235, 60, 151, 98, 96, 3, 100, 248, 118, 42, 117, 172, 211, 181, 203, 61,
   126, 156, 87, 149, 224, 55, 132, 186, 63, 238, 255, 85, 83, 152, 33, 160,
   184, 210, 219, 159, 11, 180, 194, 130, 212, 147, 5, 215, 92, 27, 46, 113,
   187, 52, 25, 185, 79, 221, 48, 70, 31, 101, 15, 195, 201, 50, 222, 137,
   233, 229, 106, 122, 183, 178, 177, 144, 207, 234, 182, 37, 254, 227, 231, 54,
   209, 133, 65, 202, 69, 237, 220, 189, 146, 120, 68, 21, 125, 38, 30, 2,
   155, 53, 196, 174, 176, 51, 246, 167, 76, 110, 20, 82, 121, 103, 112, 56,
   173, 49, 217, 252, 0, 114, 228, 123, 12, 93, 161, 253, 232, 240, 175, 67,
   128, 22, 158, 89, 18, 77, 109, 190, 17, 62, 4, 153, 163, 59, 145, 138,
   7, 74, 205, 10, 162, 80, 45, 104, 111, 150, 214, 154, 28, 191, 169, 213,
   88, 193, 198, 200, 245, 39, 164, 124, 84, 78, 1, 188, 170, 23, 86, 226,
   141, 32, 6, 131, 127, 199, 40, 135, 16, 57, 71, 91, 225, 168, 242, 206,
   97, 166, 44, 14, 90, 236, 239, 230, 244, 223, 108, 102, 119, 148, 251, 29,
   216, 8, 9, 249, 208, 24, 105, 94, 34, 64, 95, 115, 72, 134, 204, 43,
   247, 243, 218, 47, 58, 73, 107, 241, 179, 116, 66, 36, 143, 81, 250, 139,
   19, 13, 142, 140, 129, 192, 99, 171, 157, 136, 41, 75, 35, 165, 26);
 table1: array [0..255] of Byte = (
   170, 42, 95, 141, 109, 30, 71, 89, 26, 147, 231, 205, 239, 212, 124, 129, 216,
   79, 15, 185, 153, 14, 251, 162, 0, 241, 172, 197, 43, 10, 194, 235, 6,
   20, 72, 45, 143, 104, 161, 119, 41, 136, 38, 189, 135, 25, 93, 18, 224,
   171, 252, 195, 63, 19, 58, 165, 23, 55, 133, 254, 214, 144, 220, 178, 156,
   52, 110, 225, 97, 183, 140, 39, 53, 88, 219, 167, 16, 198, 62, 222, 76,
   139, 175, 94, 51, 134, 115, 22, 67, 1, 249, 217, 3, 5, 232, 138, 31,
   56, 116, 163, 70, 128, 234, 132, 229, 184, 244, 13, 34, 73, 233, 154, 179,
   131, 215, 236, 142, 223, 27, 57, 246, 108, 211, 8, 253, 85, 66, 245, 193,
   78, 190, 4, 17, 7, 150, 127, 152, 213, 37, 186, 2, 243, 46, 169, 68,
   101, 60, 174, 208, 158, 176, 69, 238, 191, 90, 83, 166, 125, 77, 59, 21,
   92, 49, 151, 168, 99, 9, 50, 146, 113, 117, 228, 65, 230, 40, 82, 54,
   237, 227, 102, 28, 36, 107, 24, 44, 126, 206, 201, 61, 114, 164, 207, 181,
   29, 91, 64, 221, 255, 48, 155, 192, 111, 180, 210, 182, 247, 203, 148, 209,
   98, 173, 11, 75, 123, 250, 118, 32, 47, 240, 202, 74, 177, 100, 80, 196,
   33, 248, 86, 157, 137, 120, 130, 84, 204, 122, 81, 242, 188, 200, 149, 226,
   218, 160, 187, 106, 35, 87, 105, 96, 145, 199, 159, 12, 121, 103, 112);

procedure _comp128v23_internal(output, kxor, rand: PByte);
var
 temp: array [0..15] of Byte;
 km_rm: array [0..31] of Byte;
 i,j,k,z: Byte;
begin
 ZeroMemory(@temp[0], SizeOf(temp));
 CopyMemory(@km_rm[0], rand, 16);
 CopyMemory(@km_rm[16], kxor, 16);

 for i := 0 to 4 do
 begin
   for z := 0 to 15 do
     temp[z] := table0[table1[km_rm[16+z]] xor km_rm[z]];

   j := 0;
   while (1 shl i) > j do
   begin
     k := 0;
     while (1 shl (4-i)) > k do
     begin
       km_rm[((2*k+1) shl i)+j] := table0[table1[temp[(k shl i)+j]] xor (km_rm[(k shl i)+16+j])];
       km_rm[(k shl (i+1))+j] := temp[(k shl i)+j];
       Inc(k);
     end;
     Inc(j);
   end;
 end;

 ZeroMemory(output, 16);
 for i := 0 to 15 do
   for j := 0 to 7 do
     output[i] := output[i] xor (((km_rm[(19*(j+8*i)+19) mod 256 div 8] shr (3*j+3) mod 8) and 1) shl j);
end;

///*! Perform COMP128v3 algorithm
//*  \param[in] ki Secret Key K(i) of subscriber
//*  \param[in] rand Random Challenge
//*  \param[out] sres user-supplied buffer for storing computed SRES value
//*  \param[out] kc user-supplied buffer for storing computed Kc value
//*  \returns 0 */
function comp128v3(ki, rand, sres, kc: PByte): Integer;
var
 k_mix: array [0..15] of Byte;
 rand_mix: array [0..15] of Byte;
 katyvasz: array [0..15] of Byte;
 output: array [0..15] of Byte;
 i: Byte;
begin
 ZeroMemory(@k_mix[0], 16);
 ZeroMemory(@rand_mix[0], 16);
 ZeroMemory(@katyvasz[0], 16);
 ZeroMemory(@output[0], 16);

 for i := 0 to 7 do
 begin
   k_mix[i] := ki[15 - i];
   k_mix[15 - i] := ki[i];
 end;

 for i := 0 to 7 do
 begin
   rand_mix[i] := rand[15 - i];
   rand_mix[15 - i] := rand[i];
 end;

 for i := 0 to 15 do
   katyvasz[i] := k_mix[i] xor rand_mix[i];

 for i := 0 to 7 do
   _comp128v23_internal(@rand_mix[0], @katyvasz[0], @rand_mix[0]);

 for i := 0 to 15 do
   output[i] := rand_mix[15-i];

 move(output[8], output[4], 8); //* ignore bytes 4..7 */

///* the algorithm uses 16 bytes until this point, but only 12 bytes are effective
// * also 12 bytes coming out from the SIM card */

 move(output[0], sres[0], 4);
 move(output[4], kc[0], 8);

 Result := 0;
end;

///*! Perform COMP128v2 algorithm
//*  \param[in] ki Secret Key K(i) of subscriber
//*  \param[in] rand Random Challenge
//*  \param[out] sres user-supplied buffer for storing computed SRES value
//*  \param[out] kc user-supplied buffer for storing computed Kc value
//*  \returns 0 */
function comp128v2(ki, rand, sres, kc: PByte): Integer;
begin
 Result := comp128v3(ki, rand, sres, kc);
 kc[7] := 0; //* 10 last bits of Kc forced to 0 */
 kc[6] := kc[6]  and $fc;
end;

begin
 try

 except
   on E: Exception do
     Writeln(E.ClassName, ': ', E.Message);
 end;
end.


cryptologic ©   (24.03.21 22:19[19]


> Rouse_ ©   (24.03.21 21:15) [18]
> А зачем это тебе если ты простейший сишный исходник на дельфю
> конвернуть не можешь?


Могу, но времени нет...  этот код давно валяется уже почти скоро год будет, а руки все не как не доходят, все откладываю да откладываю... куча дел других более важных наваливается. Не тот случай был, что бы все бросить и этой фигней заняться.

Теперь самая главная задача осталась. Как проверить что сей алгоритм рабочий? Кто даст гарантию, что именно этот алгоритм и есть правильный? Может его от фонаря китайские шалопаи слили.

А зачем он мне нужен был вот сейчас уже точно не помню, но вот нужен был...

Ну все равно спасибо товарищ майор или как там вас товарищ полковник.. ;-)


cryptologic ©   (24.03.21 22:44[20]


> cryptologic ©   (24.03.21 22:19) [19]


Когда то comp128v1 очень легко ломался без проблем. У меня были симки-болванки я ломал симки и записывал кучу номеров на одну болванку так называемую мультисим.. Пока все ОПСОСы не перешли на v2 b v3. Ну и вот пришла идея как можно попробовать в целях эксперимента т.е. спортивного интереса взломать симку версии 2 или версии 3. Метод примерно такой сим карте посылаем заведомо известый челенж, например, "AA... AAA" или "00.. ..00", а от симки получаем хешь, алгоритм этого хеша допустим условно "известен" вы только что сами написали... дальше нужно сделать программу для брут форса с распределенным вычислением по узлам... или будет найден реальный ключ симки или коллизия ключа..  потом симку можно будет также клонировать и на мультисим v2 записать кучу номеров.  В некоторых странах это не запрещено например Китай. И все потом можно ПО продать в Китай.  :-)


cryptologic ©   (24.03.21 23:52[21]

Не менее сложной задачей является отправить сим карте в правильном формате запрос на получения хэша. Но есть некоторая программа которая ломает сим карты через специальный адаптер, который подключается к СОМ порту.  Метод заключается в том, что бы перехватить  буфер СОМ порта программой "Serial Port Monitor" и посмотреть в каком порядке программа simscan посылает команды к сим карте.
Я таким методом исследовал как управляются китайские usb реле их фирменной убогой программой, а потом свою программу сделал.


cryptologic ©   (25.03.21 01:38[22]


> Rouse_ ©   (24.03.21 21:15) [18]


Еще раз спсбл скажи куда тебе крипту загнать?  Хочу 100 RVN кинуть вознаграждения


cryptologic ©   (25.03.21 01:47[23]

Если нет крипто кошелька то я бы посоветовал TrustWallet на сматрфон, или SafePal есть версия аппаратная самая надежная. Сейчас вообще модно иметь криптовалюту, даже Илон Маск вваливает свои миллионы в крипту.


Rouse_ ©   (25.03.21 10:10[24]


> cryptologic ©   (25.03.21 01:38) [22]
> Еще раз спсбл скажи куда тебе крипту загнать?  Хочу 100
> RVN кинуть вознаграждения

Себе оставь, там делов на 5 минут, не за что таньга требовать :)))))


manaka ©   (25.03.21 15:47[25]


> Как проверить что сей алгоритм рабочий?

Для этого надо сравнить результат с заведомо верным. )))


cryptologic ©   (26.03.21 09:23[26]


> manaka ©   (25.03.21 15:47) [25]


Правильно, а поэтому нужно достать реально работающую симку v2  и её Ki для проверки, а где? Вариан 2) самый трудный и тупой взломать симку v2 выше описанным способом и записать ее на болванку, потом проверить на ОПСОСе
Вариант 3, выпаять GSM модуль сделать имитацию СИМ и кидать ОПСОСу  запросы на аунтификацию но вместо реального Ki симки сгенерированый в случайном порядке по известному алгоритму... а вдруг повезет и удастся чужой Ki захватить.


manaka ©   (27.03.21 16:54[27]


> Для этого надо сравнить результат с заведомо верным.

Я не о том. Если есть заведомо верный результат, значит есть рабочий алгоритм его нахождения.
;)


cryptologic ©   (29.03.21 22:43[28]


> manaka ©   (27.03.21 16:54) [27]
>


Наверно, но я же предпочту вернуться к своим баранам, т.е. к той теме с которой начал.
Скажу сразу же где мне нужны фукции проверки контроля четности флетчера для проверки четности сообщений для ардуино т.к. в ардуино ограничена память, то естественно CRC16,  CRC32, использующие таблицы не пригодны т.к. сильный расход память.  Флетчер подойдёт.
Ну так кто то скажет используй готовый код из примера https://ru.wikipedia.org/wiki/Контрольная_сумма_Флетчера - да и будет прав. Но мне нужно код на делфи, так как ардуино будет управляться с ПС, а на ПС программа на разрабатывается на Delphi, а значит нужно такая же функция как и на Си

И по мимо 16 битной функции мне нужны функции 8,16, 32, 64 битные т.е. все функции флетчера..  Но я на самом деле в Си не очень хорошо разбираюсь и многие операторы "финделябры" языка не понятны.

Кстати, что ранее были здесь показаны фунции на делфи Fletcher32 и Fletcher64 они не правильные и не работают..  т.к. их результаты даже близко не правильны с  примерами из статьи из "вики".


cryptologic ©   (30.03.21 01:22[29]

Короче у меня в место результата

16-битная реализация (32-битная контрольная сумма)
"abcde"    -> 4031760169 (0xF04FC729)
"abcdef"   -> 1448095018 (0x56502D2A)
"abcdefgh" -> 3957429649 (0xEBE19591)


32-битная реализация (64-битная контрольная сумма)
"abcde"  -> 14467467625952928454 (0xC8C6C527646362C6)
"abcdef" -> 14467579776138987718 (0xC8C72B276463C8C6)


- получается один результат:
Fletcher32(AnsiString('abcde')) : 495 hex: 01EF
Fletcher64(AnsiString('abcde')) : 495 hex: 000001EF


Получается, что операция   OR sum1 затирает значения sum2 так как в sum1 в старших битах всегlа нули [0][0][1][1] получается, что алгоритм работает если подавать данные по два 2 байта а не по одному..  если подавать по 1 байту в UInt32 то получается, что старшие байты пустые.


cryptologic ©   (30.03.21 05:00[30]

Переделал функцию так что бы она по 2 байта записывала в Uint16 а не по одному и все равно результаты не сходятся .... печалька

{-------------------------------- Fletcher32 ----------------------------------}
function Fletcher32(AStrData: AnsiString): UInt32;
var
 sum1, sum2: UInt32;
 ch: AnsiString;
 //ch: AnsiChar;
 pos: integer;
begin
 sum1   := 0;
 sum2   := 0;

 {  // Версия 1
 for ch in AStrData do
 begin
   sum1 := (sum1 + Byte(ch)) mod $FFFF;
   sum2 := (sum2 + sum1) mod $FFFF;
   // Form1.mm.lines.add('sum1: '+ IntToStr(sum1) + ' sum2: '+ IntToStr(sum2));
 end;
 Result := (sum2 shl 16) or sum1;  }

 // Версия 2
 pos  := 1;
 while pos <= Length(AStrData) do
 begin
   ch := copy(AStrData, pos, 2);
   if Length(ch) = 2 then
   begin
     sum1 := sum1 + (($0000 or Byte(ch[1])) shl 8) or Byte(ch[2]) mod $FFFF;
   end
   else
   begin
     sum1 := (sum1 + ($0000 or Byte(ch[1])) shl 8) mod $FFFF;
   end;
   // Form1.mm.Lines.Add('pos' + IntToStr(pos) + 'ch: ' + ch );
   pos := pos + 2;
   sum2 := (sum2 + sum1) mod $FFFF;
 end;

 Result := (sum2 shl 16) or sum1;

end;


Теперь у меня такой результат вываливается Fletcher32 "abcde": 10695 hex: 000029C7


KSergey ©   (30.03.21 09:16[31]

Слов много, а в чем конкретно проблема - не понять.
Приведите код Си-функции, которую надо переложить (прямо здесь, не ссылкой куда-то!!) - тогда можно вести предметный разговор.


KSergey ©   (30.03.21 09:29[32]

Кстати, если брать примеры из вики
Там такой заголовок:

uint32_t
fletcher32(const uint16_t *data, size_t len)

И приведены примеры:
16-битная реализация (32-битная контрольная сумма).
"abcde"    -> 4031760169 (0xF04FC729)

Если я верно понимаю - то этот пример соответствует приведённому мной заголовку функции. Так? или не так?

Если так - то какие данные должны приезжать на вход этой функции? я вот не понимаю. Что именно (побайтно) должно быть в памяти, на которую указывает *data ? как надо интерпретировать строку "abcde" ??

Вижу три варианта (ниже коды символов в hex, т.е. 'a' - это 61 и т.д.):
1) 61 62 63 64 65 00
и len = 3 (ну это же количество uint16_t слов, так? или байтов??!)

2) 00 61 00 62 00 63 00 64 00 65
и len = 5

3) 61 00 62 00 63 00 64 00 65 00
и len = 5

Вот что авторы хотели сказать??


KSergey ©   (30.03.21 09:39[33]

Проверил тут
https://onlinegdb.com/B1z_UHgrd

Верный вариант 1)

т.к. вызов вот в таком виде
fletcher32((const uint16_t *)"abcde", 3);
даёт то же результат, что в вики

Тогда вот это

> cryptologic ©   (30.03.21 05:00) [30]
>
> function Fletcher32(AStrData: AnsiString): UInt32;

никак не эквивалентно Cи-заголовку функции
uint32_t
fletcher32(const uint16_t *data, size_t len)

т.к. AnsiString - однобайтная.

Если же все-таки хочется сделать именно такой заголовок (в принципе, разумно), то надо не забывать, что при нечетном кол-ве символов в строке надо еще не забывать учитывать финальный #0 (ну или "добавлять" его в рассчет.


KSergey ©   (30.03.21 09:45[34]

Если хочется в дельфи иметь заголовок как приведён, то я бы сделал перегруженный вариант с заголовком

function Fletcher32(data: PUint32, len: UInt32): UInt32;

которую бы вызывал

function Fletcher32(AStrData: AnsiString): UInt32;
var
len: UInt32
begin
  len := как-то вычисляем так, чтобы для четной длины AStrData было Length(AStrData) / 2, а для нечетного Length(AStrData) / 2 + 1, лень думать как

  Result := Fletcher32((PUint32)PChar(AStrData), len);
end;

ну а вариант
function Fletcher32(data: PUint32, len: UInt32): UInt32;
добуквенно переложить из Си-реализации и работу с указателями, без всяких там
ch := copy(AStrData, pos, 2);


cryptologic ©   (30.03.21 20:15[35]


> KSergey ©   (30.03.21 09:29) [32]



> Если я верно понимаю - то этот пример соответствует приведённому
> мной заголовку функции. Так? или не так?


Так


> Если я верно понимаю - то этот пример соответствует приведённому
> мной заголовку функции. Так? или не так?
>
> Если так - то какие данные должны приезжать на вход этой
> функции? я вот не понимаю. Что именно (побайтно) должно
> быть в памяти, на которую указывает *data ? как надо интерпретировать
> строку "abcde" ??


На вход функции должны приезжать строковые данные "abcde" - это пример строки из статьи wiki - они же будут проверочными.


> Вижу три варианта (ниже коды символов в hex, т.е. 'a' -
> это 61 и т.д.):
> 1) 61 62 63 64 65 00
> и len = 3 (ну это же количество uint16_t слов, так? или
> байтов??!)
>
> 2) 00 61 00 62 00 63 00 64 00 65
> и len = 5
>
> 3) 61 00 62 00 63 00 64 00 65 00
> и len = 5
>
> Вот что авторы хотели сказать??
>
>


Ну да даже на си возникают проблемы с подачей байтов.  Как нужно вписывать однобайтовый массив строки в двух байтовый массив когда есть четные и не четные строки.


cryptologic ©   (30.03.21 20:24[36]


> KSergey ©   (30.03.21 09:39) [33]



> Если же все-таки хочется сделать именно такой заголовок
> (в принципе, разумно), то надо не забывать, что при нечетном
> кол-ве символов в строке надо еще не забывать учитывать
> финальный #0 (ну или "добавлять" его в рассчет.


Я как бы учел его добавление

>    if Length(ch) = 2 then
>    begin
>      sum1 := sum1 + (($0000 or Byte(ch[1])) shl 8) or Byte(ch[2])
> mod $FFFF;
>    end
>    else
>    begin
>      sum1 := (sum1 + ($0000 or Byte(ch[1])) shl 8) mod $FFFF;
>
>    end;


смещение последнего нечетного байта в лево на 8 бит в последней элемент массива т.е.
[0][x] shl 8  = [x][0]  т.е. это как бы я этим дописал недостающий ноль.


cryptologic ©   (30.03.21 20:32[37]

Короче говоря нужно эту функцию транслировать в код  Delphi

uint32_t fletcher32(const uint16_t *data, size_t len)
{
       uint32_t c0, c1;
       unsigned int i;

       for (c0 = c1 = 0; len >= 360; len -= 360) {
               for (i = 0; i < 360; ++i) {
                       c0 = c0 + *data++;
                       c1 = c1 + c0;
               }
               c0 = c0 % 65535;
               c1 = c1 % 65535;
       }
       for (i = 0; i < len; ++i) {
               c0 = c0 + *data++;
               c1 = c1 + c0;
       }
       c0 = c0 % 65535;
       c1 = c1 % 65535;
       return (c1 << 16 | c0);
}


Ноя в си не силен и не могу понять условия циклов, а потом следующее о чем выше упоминалось
> KSergey ©   (30.03.21 09:39) [33]


как вписывать строки в двухбайтные массивы когда строки могут быть четными и не четными по своей длине. В wiki приводятся примеры именно со строками и результаты по которым можно будет проверить, что транслированный код работает правильно.


cryptologic ©   (30.03.21 20:37[38]


> KSergey ©   (30.03.21 09:45) [34]


Еще мне бы хотелось, что бы заголовок функции в delphi интерпретации был таким
function Fletcher32(AStrData: AnsiString): UInt32;
потому  что это упрощает работу с данными, т.к. данные  почти всегда будут строками


cryptologic ©   (30.03.21 20:44[39]

Я так понимаю, что данные должны подаваться таким образом
при четной подаче байт   xxxxxx -> [xx][xx][xx]
при не четной подаче байт xxxxx -> [xx][xx][x0]

Где xxxxxx - однобайтная строка
где [xx] - 2х байтный тип Uint16


cryptologic ©   (30.03.21 22:16[40]

uint32_t
> cryptologic ©   (30.03.21 20:32) [37]


Выше упомянутая функция это оптимизированная.

Это не оптимизированная  функция. Ее проверил работает?
Но вот по ней делаю на Delphi и результат  не выходить  три варианта испробовал ничего не выходит...  у меня возникает подозрение, что косяки вылазит на действиях с бинарной математикой  не корректно складываются числа, может это из-за супернового процессора  
Получается (sum2 shl 16) or sum1; какие бы значения в sum2 небыли после or в старших байтах остаются только 00 выход всегда выглядит так  [00XX]  ... вообще не пойму как он так складывает?  Проц. супер новый Ryzen 9 5950X или косяки в компиляторе.

fletcher32(const uint16_t *data, size_t len)
{
  uint32_t sum1 = 0;
  uint32_t sum2 = 0;

  for(int index = 0; index < len; ++index ) {
     sum1 = (sum1 + data[index]) % 0xffff;
     sum2 = (sum2 + sum1) % 0xffff;
  }
  return (sum2 << 16) | sum1;
}


KSergey ©   (31.03.21 06:42[41]

> cryptologic ©   (30.03.21 20:44) [39]
>
> Я так понимаю, что данные должны подаваться таким образом

Да, я про это уже написал - верный вариант 1 из KSergey ©   (30.03.21 09:29) [32]


KSergey ©   (31.03.21 06:44[42]

> cryptologic ©   (30.03.21 22:16) [40]
> Выше упомянутая функция это оптимизированная.
>
> Это не оптимизированная  функция. Ее проверил работает?

Вы уж как-нибудь сами проверяйте, я выше давал ссылку на онлайн-компилятор, там всё это можно и легко.


KSergey ©   (31.03.21 07:26[43]

Пробовать здесь:
https://onlinegdb.com/HkGecdWr_

type
   PUInt16 = ^UInt16;

function fletcher32(data: PUInt16; len: UInt32): UInt32;
var
      c0, c1: UInt32;
      i: UInt32;
begin
       c0 := 0;
       c1 := 0;
       while len >= 360 do
       begin
              for i := 1 to 360 do
              begin
                      c0 := c0 + data^;
                      c1 := c1 + c0;
                      Inc(data);
              end;
              c0 := c0 mod 65535;
              c1 := c1 mod 65535;
              len := len - 360;
      end;
      for i := 1 to len do
      begin
              c0 := c0 + data^;
              c1 := c1 + c0;
              Inc(data);
      end;
      c0 := c0 mod 65535;
      c1 := c1 mod 65535;
      {Result}fletcher32 := (c1 shl 16) or c0;
end;

function fletcher32(data: AnsiString): UInt32;
var
   len: UInt32;
begin
   len := 3;   // TODO: сделать верный алгоритм вычисления len через длину переданной строки
   {Result}fletcher32 := fletcher32(PUInt16(PAnsiChar(data)), len)
end;

begin
 writeln (fletcher32('abcde'));
end.


KSergey ©   (31.03.21 07:30[44]

Кстати, что там будет для строк, когда len > 360 - не проверял.


cryptologic ©   (31.03.21 21:38[45]


> KSergey ©   (31.03.21 07:30) [44]
> Кстати, что там будет для строк, когда len > 360 - не проверял.
>


Сам не знаю,  то же не проверял..

Ваш код работает, огромное спасибо.
Вы мне просто глаза открыли как через указатели один тип данных вписать в другой.


cryptologic ©   (01.04.21 06:47[46]

Опубликовал модуль:  
https://github.com/superbot-coder/additional_modules/blob/master/Fletcher.pas

Пока только с функциями без оптимизации, позже после дополнительной проверки добавлю с оптимизированными функциями.


cryptologic ©   (01.04.21 07:03[47]


> cryptologic ©   (30.03.21 20:44) [39]


В действительности последний блок данных при не четном количестве данных заполняется
так 'abcde' - > Uint16 [ab][cd][0e] или [abcd][000e] ,  а не так как я предполагал [ab][cd][e0] или Uint32 [abcd][e000]... Просто все подгоняют результаты под статью в википедии, но никто не усомнился, а что если в самой википедии неправильно?


cryptologic ©   (01.04.21 07:17[48]


> cryptologic ©   (01.04.21 07:03) [47]
>

Я когда то в бурные годы молодости взламывал VPN`ки (причем удачно) и для этого копался в RFC стандартах и тоже находил кучу несоответствий описанных в RFC с действительностью, там порой так размыто и не определенно описаны стандарты, что если делать как написано, то никoгда в жизни не получить желаемого результата - это будет выглядеть как попытка натянуть сову на глобус.


KSergey ©   (01.04.21 07:38[49]

> cryptologic ©   (01.04.21 07:03) [47]
> В действительности последний блок данных при не четном количестве данных заполняется
> так 'abcde' - > Uint16 [ab][cd][0e]

Не понятно почему 0 и е поменяны местами, а все остальное - нет.
Явно же все поменяно местами, это ж Intel


cryptologic ©   (01.04.21 11:52[50]


> KSergey ©   (01.04.21 07:38) [49]
> > cryptologic ©   (01.04.21 07:03) [47]
> > В действительности последний блок данных при не четном
> количестве данных заполняется
> > так 'abcde' - > Uint16 [ab][cd][0e]
>
> Не понятно почему 0 и е поменяны местами, а все остальное
> - нет.
> Явно же все поменяно местами, это ж Intel


Ну, да так то же подумал, что наверно влияет обратный порядок байт или прямой.
На  самом деле размещение  всех остальных байтов не смотрел, а нужно посмотреть. Но Но во нули дописывать точно не нужно они там уже лежат. Я вообще думал, что через указатели можно мусор зацепить в последнем блоке, когда он выходит за пределы строки. Но мусора нет,  это может быть процы современные имеют технологию защиты от выхода за пределы адресного пространства. Помнится, что все эти сишные кодеры всегда грешили неконтролируемым переполнением буферов и не контролируемым чтением памяти, кстати это классический сишный глюк. Вписывать одни данные в другие не контролируя размер буфера в надежде, что ничего "плохого" не случится.


KSergey ©   (01.04.21 13:05[51]

Мусор там, конечно, будет
Просто при обращении через PUInt16 нам везёт, т.к. PAnsiChar() гарантированно возвращает строку с 0 байтом на конце.

А вот обращение по PUint32 (ну в смысле каст к такому указателю) дас нам тут мусор, конечно, или вообще вылет за границы памяти.

> cryptologic ©   (01.04.21 06:47) [46]
>
> Опубликовал модуль:  
> https://github.com/superbot-coder/additional_modules/blob/master/Fletcher.pas


   sum1 := (sum1 + PUint32(AStrData)^) mod $FFFFFFFF;


cryptologic ©   (01.04.21 17:32[52]


> KSergey ©   (01.04.21 13:05) [51]
> Мусор там, конечно, будет
> Просто при обращении через PUInt16 нам везёт, т.к. PAnsiChar()
> гарантированно возвращает строку с 0 байтом на конце.


Смотрел в Uint32 и в Uint64  ратина одна чисто, может просто всегда везет и область памяти за пределами строки чистая или же так отрабатывает компилятор не дает взять данные за пределами строки.


cryptologic ©   (01.04.21 17:33[53]


> KSergey ©   (01.04.21 13:05) [51]


> sum1 := (sum1 + PUint32(AStrData)^) mod $FFFFFFFF;
>
>

А что тут не так?


cryptologic ©   (01.04.21 17:35[54]

Кстати не я только сомневался в правильность кода, вот еще поднималась дискуссия
https://stackoverflow.com/questions/40270450/correctness-of-fletcher32-checksum-algorithm


cryptologic ©   (01.04.21 17:47[55]


> KSergey ©   (01.04.21 13:05) [51]
> Мусор там, конечно, будет


Я ни водном примере в не нашел кто бы заморачивался и чистил конец последний болк получаемых данных при не четных входных данных


KSergey ©   (02.04.21 07:11[56]

> cryptologic ©   (01.04.21 17:47) [55]
> Я ни водном примере в не нашел кто бы заморачивался и чистил
> конец последний болк получаемых данных при не четных входных данных

Вывод прост: примеры делают не очень квалифицированные люди.


KSergey ©   (02.04.21 07:15[57]

>  cryptologic ©   (01.04.21 17:33) [53]
> > sum1 := (sum1 + PUint32(AStrData)^) mod $FFFFFFFF;

Возьмите бумагу в клеточку
Распишите как в памяти выглядит побайтно строка "abcde"
далее двигая указатель в выражении PUint32(AStrData)^ обводите те группы байтов, которые будут считываться из памяти. И вам всё станет понятно.

Надо всегда помнить, что при обращении за пределы выделенного куска памяти - всё что угодно может происходить. И мусор, и access violation и все что угодно.


KSergey ©   (02.04.21 07:19[58]

>  cryptologic ©   (01.04.21 17:32) [52]
> Смотрел в Uint32 и в Uint64  ратина одна чисто, может просто всегда везет и область памяти за пределами строки чистая
> или же так отрабатывает компилятор не дает взять данные за пределами строки.

В простейшем модельном примере, да еще в дебаге - это совсем не то, что в релизе и реальной программе.
Мне лень подбирать какой-то демонстрационный пример, с ходу ведь не придумаешь как так заставить появиться мусору.
Попробуйте, например, что-то такое, вдруг повезёт:

str := "abcfeyz";
SetLength(str, 5);


KSergey ©   (02.04.21 09:23[59]

> KSergey ©   (02.04.21 07:11) [56]
>
> > cryptologic ©   (01.04.21 17:47) [55]
> > Я ни водном примере в не нашел кто бы заморачивался и
> чистил
> > конец последний болк получаемых данных при не четных входных
> данных
>
> Вывод прост: примеры делают не очень квалифицированные люди.
>

Впрочем, тут бы пример, конечно, ссылку где такое.


cryptologic ©   (02.04.21 23:46[60]


> KSergey ©   (02.04.21 07:19) [58]


Но вот по сути это же хакерский метод указать длину строки  10 байт а пытаться прочитать гигабайт, а еще можно залезть в адресное пространство соседнего процесса и считать там приватный блок данных, например с ключами шифрования - это ничего не напоминает?
Сейчас на современных процессорах уже внедряются подобные защиты как от Spectre, Meltdown,  переполнения буфера и попытка чтение данных за пределами адресного пространстве, то что защита от переполнения буфера уже точно реализована, а вот второе нужно поинтересоваться как называется и вообще реализована ли в природе.

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

я  предлагаю такой код, основанный на том что бы почистить только последний блок

function Fletcher64(AStrData: PAnsiChar): UInt64;
var
 sum1, sum2: UInt64;
 sum0, len, i: UInt32;
 rem: Byte; // Remainder of division
Type
 PUint32 = ^Uint32;
begin
 sum1 := 0;
 sum2 := 0;
 len := Length(PAnsiChar(AStrData));
 // Uint32 размер чтения входящего блока
 rem  := (len mod SizeOf(sum0));

 // Определение четности
 if rem = 0 then len := len div 4
 else Len := (Len div 4) + 1;

 for i := 1 to len do
 begin
   sum0  := PUint32(AStrData)^;
   // Определяем, что блок последний
   if i = len then
   begin
     //сдвигает байты влево, а затем обратно что бы почисть от возможного мусора
     case rem of
       1: sum0 := (sum0 shl 24) shr 24;
       2: sum0 := (sum0 shl 16) shr 16;
       3: sum0 := (sum0 shr 8) shr 8;
     end;
   end;
   sum1 := (sum1 + sum0) mod $FFFFFFFF;
   sum2 := (sum2 + sum1) mod $FFFFFFFF;
   Inc(PUint32(AStrData));
 end;
 Result := (sum2 shl 32) or sum1;

end;


cryptologic ©   (02.04.21 23:51[61]


> cryptologic ©   (02.04.21 23:46) [60]


сорри...

в строке 29 ошибочка   3: sum0 := (sum0 shr 8) shr 8;
имелось виду так sum0 := (sum0 shl 8) shr 8;


manaka ©   (03.04.21 16:32[62]

А вам не кажется, что вы занимаетесь тем, что запрещено правилами форума?

Запрещается:
6. Публиковать или искать серийные номера, коды а также алгоритмы взлома того или иного программного обеспечения


KSergey ©   (06.04.21 08:29[63]

> cryptologic ©   (02.04.21 23:46) [60]
> Но вот по сути это же хакерский метод указать длину строки
>  10 байт а пытаться прочитать гигабайт

> это ничего не напоминает?

Напоминает.
Криворукость глючного софта.


KSergey ©   (06.04.21 08:33[64]

> sum0  := PUint32(AStrData)^;

Нельзя так. Просто нельзя.
Именно на таком вот криворуком говнокоде под девизом "а у меня работает!" потом и резвятся разные "хакеры".

Если не хочется делать копию входного буфера для "добивания" до нужного числа байтов - то надо корректно обыграть обработку вычитывания финальных байтов, раз уж вот это вот всё началось:


>     // Определяем, что блок последний
>     if i = len then
>     begin
>       //сдвигает байты влево, а затем обратно что бы почисть
> от возможного мусора
>       case rem of
>


KSergey ©   (06.04.21 08:36[65]

PS
Удивительно: рядом бурно обсуждаются какие-то сериалы и прочие убийство времени впустую, а в этой осмысленной в общем-то ветке - тишина.

Скажите, что я не понимаю?


cryptologic ©   (08.04.21 06:49[66]


> KSergey ©   (06.04.21 08:33) [64]
> > sum0  := PUint32(AStrData)^;


Может так и не льзя, я не знаю как это будет выглядеть на ассемблере, но именно такой код дает более высокую производительность где то на 30% быстрее чем просто sum0  := PUint32(AStrData)  - измерял эмпирическим путем.
> Если не хочется делать копию входного буфера для "добивания"
> до нужного числа байтов - то надо корректно обыграть обработку
> вычитывания финальных байтов, раз уж вот это вот всё началось:
>
>
>
> >     // Определяем, что блок последний
> >     if i = len then
> >     begin
> >       //сдвигает байты влево, а затем обратно что бы почисть
> > от возможного мусора
> >       case rem of
> >


function Fletcher64(AStrData: PAnsiChar): UInt64;
var
 sum1, sum2: UInt64;
 sum0, len, i: UInt32;
 rem, shift: Byte; // Remainder of division
Type
 PUint32 = ^Uint32;
begin
 sum1 := 0;
 sum2 := 0;
 len := Length(PAnsiChar(AStrData));
 // Uint32 размер чтения входящего блока 4 байта
 rem   := (len mod 4);
 // (4 байта - rem остаток ) * 8 bit
 shift := (4 - rem) * 8;

 // Определение четности
 if rem = 0 then len := len div 4
 else Len := (Len div 4) + 1;

 for i := 1 to len do
 begin
   sum0  := PUint32(AStrData);
   // Определяем, что блок последний
   // Сдвигает байты влево, а затем обратно, что бы почисть от возможного
   if i = len then sum0 := (sum0 shl shift) shr shift;
   sum1 := (sum1 + sum0) mod $FFFFFFFF;
   sum2 := (sum2 + sum1) mod $FFFFFFFF;
   Inc(PUint32(AStrData));
 end;

 Result := (sum2 shl 32) or sum1;

end;


cryptologic ©   (08.04.21 07:14[67]


> cryptologic ©   (08.04.21 06:49) [66]


Поторопился с кодом
Имелось ввиду как то так..

function Fletcher64(AStrData: PAnsiChar): UInt64;
var
 sum1, sum2: UInt64;
 sum0, len, i: UInt32;
 rem, shift: Byte; // Remainder of division
Type
 PUint32 = ^Uint32;
begin
 sum1  := 0;
 sum2  := 0;
 shift  := 0;
 len := Length(PAnsiChar(AStrData));
 // Uint32 размер чтения входящего блока 4 байта
 rem   := (len mod 4);
 // Определение четности
 if rem = 0 then len := len div 4
 else
 begin
   shift := (4 - rem) * 8; // если rem <> 0
   Len := (Len div 4) + 1;
 end;

 for i := 1 to len do
 begin
   sum0  := PUint32(AStrData)^;
   sum0  := sum0;
   // Определяем, что блок последний
   // Сдвигает байты влево, а затем обратно,
   // что бы почисть от возможного мусора
   if (i = len) then sum0 := (sum0 shl shift) shr shift;
   sum1 := (sum1 + sum0) mod $FFFFFFFF;
   sum2 := (sum2 + sum1) mod $FFFFFFFF;
   Inc(PUint32(AStrData));
 end;
 Result := (sum2 shl 32) or sum1;
end;


cryptologic ©   (08.04.21 07:20[68]

Ну можно еще в строку 30
добавить дополнительное условие    
if (i = len) and (rem <> 0) then sum0 := (sum0 shl shift) shr shift;

То есть избавимся в цикле от оператора "case" - он точно был полный зашквар, зато было наглядно.


KSergey ©   (08.04.21 07:22[69]

> > > sum0  := PUint32(AStrData)^;
> дает более высокую производительность
> где то на 30% быстрее чем просто sum0  := PUint32(AStrData)

Это вот не понял. Это совершенно разные же операции.
А в свете разговоров про скорость - даже не понимаю где тут описка.


KSergey ©   (08.04.21 07:35[70]

> cryptologic ©   (08.04.21 07:14) [67]
>   for i := 1 to len do
>   begin
>     sum0  := PUint32(AStrData)^;
>     sum0  := sum0;   <----- !!!!????
>     // Определяем, что блок последний


Впрочем, я люблю надёжный код; лучше 2 раза присвоить, это надёжнее. Я тоже так порой делаю, для надёжности. ;)

Что по поводу вот этого
>     sum0  := PUint32(AStrData)^;
то я всегда предлагаю в таком случае взять листок бумаги в клетку, нарисовать в клеточках строку (байты в памяти), жирно выделить границу выделенной под строку памяти. После чего обводить по 4 клетки (в данном случае) вычитываемых данных и понять, что тут не так и что фактически вычитывается.
Если человек не понимает - я расстаюсь с ним без сожалению. Поймёт - велкам, будет смысл дальше с ним сотрудничать.
Объяснить что тут и как я, конечно могу, но штука в том, что для осознания и принятия этой штуки требуется определённое время, я не вижу для себя смысла это время ждать и наблюдать.


cryptologic ©   (08.04.21 08:46[71]


> >     sum0  := sum0;   <----- !!!!????


Это было для отладки я на этом шаге "бряк" устанавливал, потом забыл удалить  .


cryptologic ©   (08.04.21 10:03[72]


> Что по поводу вот этого
> >     sum0  := PUint32(AStrData)^;


А в чем криминал? Здесь все правильно - Это получается сокращенная форм записи, только без дополнительной переменной как у вас..  Возможно это не оптимально так как это стоит в цикле и компилятору каждый вызов придется приводить один тип к другому.

Переделал код

{------------------------------- Fletcher64 -----------------------------------}
function Fletcher64(AStrData: PAnsiChar): UInt64;
Type
 PUint32 = ^Uint32;
var
 sum1, sum2: UInt64;
 sum0, len, i: UInt32;
 rem, shift: Byte; // Remainder of division
 Pu32 : PUint32;

begin
 sum1  := 0;
 sum2  := 0;
 shift := 0;
 len := Length(PAnsiChar(AStrData));
 // Uint32 размер чтения входящего блока 4 байта
 rem   := (len mod 4);
 Pu32 := PUint32(AStrData);

 // Определение четности
 if rem = 0 then len := len div 4
 else
 begin
   shift := (4 - rem) * 8; // если rem <> 0
   Len := (Len div 4) + 1;
 end;

 for i := 1 to len do
 begin
   sum0  := Pu32^; // PUint32(AStrData);
   // Определяем, что блок последний
   // Сдвигает байты влево, а затем обратно,
   // что бы почисть от возможного мусора
   if (i = len) and (rem <> 0) then sum0 := (sum0 shl shift) shr shift;
   sum1 := (sum1 + sum0) mod $FFFFFFFF;
   sum2 := (sum2 + sum1) mod $FFFFFFFF;
   //Inc(PUint32(AStrData));
   Inc(Pu32);
 end;

 Result := (sum2 shl 32) or sum1;

end;


cryptologic ©   (08.04.21 10:28[73]


> cryptologic ©   (08.04.21 10:03) [72]
>
> > Что по поводу вот этого
> > >     sum0  := PUint32(AStrData)^;
>


Вообще не знаю, почему, но оно по правильному  такая связка
  sum0  := PUint32(AStrData)^;
  inc(PUint32(AStrData))

не должно работать,  так как а где компилятор сохраняет инкрементное смещение указателя, если переменной указателя то и нету  как здесь:

Type
PUint32 = ^Uint32;
var
Pu32 : PUint32;

Pu32 := PUint32(AStrData);
Inc(Pu32);


Но каким то образом компилятор разруливает эту ситуацию..


cryptologic ©   (08.04.21 10:33[74]


> cryptologic ©   (08.04.21 10:28) [73]
>


Получается что и первый пример без переменной работает и второй с переменной указателя работает
Мне вообще интересно как  компилятор два эти примера реализует в машинном коде или на ассемблере


KSergey ©   (08.04.21 10:51[75]

> cryptologic ©   (08.04.21 10:03) [72]
> > >     sum0  := PUint32(AStrData)^;
> А в чем криминал?

Покажите фото листочка в клеточку, где вы всё разрисовали.
Без этого нет смысла продолжать разговор.


cryptologic ©   (08.04.21 11:44[76]


> KSergey ©   (08.04.21 10:51) [75]
> > cryptologic ©   (08.04.21 10:03) [72]
> > > >     sum0  := PUint32(AStrData)^;
> > А в чем криминал?
>
> Покажите фото листочка в клеточку, где вы всё разрисовали.
>


Причем тут листочек в клеточку? Вы же то же самое делаете:
function fletcher32(data: PUInt16; len: UInt32): UInt32; - у вас заголовок объявлен с типизированной переменой-указателем, затем вы в функцию передаете другой указатель другого типа  fletcher32(PUInt16(PAnsiChar(data)), len) то есть, что происходит?  Происходи то что один тип указателя был преобразован в другой тип, а точнее указатель Data получил адрес начала строки или начало блока данных..  Такое можно описать аналогиyто Data := PUint16(PAnsiChar('abcde'));  Затем вы присваиваете разыменовываете указатель c0 := c0 + data^; и присваиваете данные на которые указывает указатель
А теперь сократим эти действия с0 := c0 + PUint16(PAnsiChar('abcde'))^  - и получаем тоже самое как в вашем коде только напрямую минуя типизированную переменную Data
На какие неправильные данные должно указывать?


cryptologic ©   (08.04.21 12:12[77]


> KSergey ©   (08.04.21 10:51) [75]
> > cryptologic ©   (08.04.21 10:03) [72]
> > > >     sum0  := PUint32(AStrData)^;
> > А в чем криминал?
>
> Покажите фото листочка в клеточку, где вы всё разрисовали.
>
> Без этого нет смысла продолжать разговор.


А на бумажках ничего давно ничего не черчу.. Хоть есть и поговорка верна, что тупой карандаш лучше острой памяти.  Просто предпочитаю текстовый блокнот и там творю всякие "художества".  

[a]  [b]  [c]   [d]   [e]
97   98  99   100  101
И вот как читаются данные из памяти fletcher64 блок чтения 32бит                                                                                                        
                      десятич.                                                                       [d   c   b   a]  
Интерация 1: 1684234849  01100100 01100011 01100010 01100001:  100  99 98 97
Интерация 2  0000000101                                                               :         0  0  0 e


KSergey ©   (08.04.21 12:13[78]

> cryptologic ©   (08.04.21 11:44) [76]
> Причем тут листочек в клеточку? Вы же то же самое делаете:

Без выходного пособия.
Удачи!


cryptologic ©   (08.04.21 12:24[79]


> KSergey ©   (08.04.21 12:13) [78]
> > cryptologic ©   (08.04.21 11:44) [76]
> > Причем тут листочек в клеточку? Вы же то же самое делаете:
>
>
> Без выходного пособия.
> Удачи!
>
>


Сорян дружище извини, что потратил твое драгоценное время...

> KSergey ©   (06.04.21 08:36) [65]
> PS
> Удивительно: рядом бурно обсуждаются какие-то сериалы и
> прочие убийство времени впустую


Можете и дальше обсуждать, что обсуждается в соседних ветках я вас в принципе не заставлял ничего делать, сами хотели отвечали, хотели не отвечали...


KSergey ©   (08.04.21 12:44[80]

> cryptologic ©   (08.04.21 12:24) [79]
> я вас в принципе не заставлял ничего делать, сами хотели отвечали, хотели не отвечали

Ожидая соответствующего отношения наличию ответов.
Но вы сами решили поступать так, как поступили.
Дело ваше.


KSergey ©   (08.04.21 13:24[81]

>  cryptologic ©   (08.04.21 12:24) [79]
> > KSergey ©   (06.04.21 08:36) [65]
> > Удивительно: рядом бурно обсуждаются какие-то сериалы
>
> Можете и дальше обсуждать, что обсуждается в соседних ветках
> я вас в принципе не заставлял ничего делать

Теперь понимаю
Верной дорогой


cryptologic ©   (10.04.21 23:08[82]

В примере который указан в википедии контрольная сумма считается в таком порядке
входные данные "abcde" ->  Uint16[ba]+[dc]+[0e] Uint32[dcba]+[000e]
В википедии в об этом указывается что нужно учитывать порядок размещения байт в памяти чисел типа Uint16, Uint32 т.е. более 1 байта и что такой проблемы с порядком не возникает в функциях fletcher8, Fletcher16 c побайтовой подачей байтов.  
Все примеры которые были здесь тоже в таком порядке.

Еще добавил две функции которые будут считать контрольную сумму в другом порядке
типа вот так "abcde"  ->  Uint16[ab]+[cd]+[e0] Uint32[abcd]+[e000]  


function Fletcher32Rev(AStrData: PAnsiChar): UInt32;
var
 sum1, sum2, len, i: UInt32;
 sum0, sum: Uint16;
 rem: Byte; // Remainder of division
 PData: PUint16;
begin
 sum1 := 0;
 sum2 := 0;
 len  := Length(PAnsiChar(AStrData));
 // Uint16 размер чтения входящего блока 2 байта
 rem  := (len mod 2);
 PData := PUint16(AStrData);

 // Определение четности
 if rem = 0 then len := len div 2
 else len := (len div 2) + 1;

 for i := 1 to len do
 begin
   sum := PData^;
   // разворачиваем байты в обратный порядок
// [ba] -> [ab]
   sum0 := ((sum0 xor sum0) or sum) shl 8;
   sum0 := sum0 or (sum shr 8);
   // Определяем, что блок последний
   // Сдвигает биты вправо, а затем обратно,
   // что бы почисть от возможного мусора в последнем блоке
   // если размер блока выходит за размер входных данных
   if (i = len) and (rem <> 0) then sum0 := (sum0 shr 8) shl 8;
   sum1 := (sum1 + sum0) mod $FFFF;
   sum2 := (sum2 + sum1) mod $FFFF;
   Inc(PData);
 end;

 Result := (sum2 shl 16) or sum1;
end;


function Fletcher64Rev(AStrData: PAnsiChar): UInt64;
var
 sum1, sum2: UInt64;
 sum, sum0, len, i: UInt32;
 rem, shift, j, b: Byte; //rem - Remainder of division
 PData : PUint32;
 
begin
 sum1  := 0;
 sum2  := 0;
 shift := 0;
 len   := Length(PAnsiChar(AStrData));
 rem   := (len mod 4); // Uint32 размер чтения входящего блока 4 байта
 PData := PUint32(AStrData);

 // Определение четности
 if rem = 0 then len := len div 4
 else
 begin
   // если rem <> 0 вычисляем сдвиг (SizeOf(sum0) - rem) * 8 Bit
   shift := (4 - rem) * 8;
   Len := (Len div 4) + 1;
 end;

 for i := 1 to len do
 begin
   sum  := PData^;
   // разворачиваем байты в обратный порядок
// Uint32[dcba] -> Uint32[abcd]
for j := 0 to 3 do
   begin
     b := (b xor b) or (sum shr (j * 8));
     sum0 := (sum0 or b);
     if i <> 3 then sum0 := sum0 shl 8;
   end;
   // Определяем, что блок последний
   // Сдвигает байты вправо, а затем обратно,
   // что бы почисть от возможного мусора в последнем блоке
   // если размер блока выходит за размер входных данных
   if (i = len) and (rem <> 0) then sum0 := (sum0 shr shift) shl shift;
   sum1 := (sum1 + sum0) mod $FFFFFFFF;
   sum2 := (sum2 + sum1) mod $FFFFFFFF;
   Inc(PData);
 end;

 Result := (sum2 shl 32) or sum1;
end;


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо