You are not logged in.
Hi,
I have below record definitions.
TStTicket = packed record
TransactionFlags: UInt32;
OptionFlags: UInt32;
ZNo: UInt16;
FNo: UInt16;
EJNo: UInt16;
TotalReceiptAmount: UInt32;
TotalReceiptTax: UInt32;
TotalReceiptDiscount: UInt32;
TotalReceiptIncrement: UInt32;
CashBackAmount: UInt32;
TotalReceiptItemCancel: UInt32;
TotalReceiptPayment: UInt32;
TotalReceiptReversedPayment: UInt32;
KasaAvansAmount: UInt32;
KasaPaymentAmount: UInt32;
invoiceAmount: UInt32;
invoiceAmountCurrency: UInt32;
KatkiPayiAmount: UInt32;
TaxFreeRefund: UInt32;
TaxFreeCalculated: UInt32;
bcdTicketDate: string;
bcdTicketTime: string;
ticketType: Byte;
totalNumberOfItems: UInt16;
numberOfItemsInThis: UInt16;
totalNumberOfPayments: UInt16;
numberOfPaymentsInThis: UInt16;
TckNo: string;
invoiceNo: string;
invoiceDate: UInt32;
invoiceType: Byte;
totalNumberOfPrinterLines: Integer;
numberOfPrinterLinesInThis: Integer;
uniqueId: Array [0..23] of Byte;
SaleInfo: Array [0..511] of TStSaleinfo;
stPayment: TStPayment;
stTaxDetails: Array [0..7] of TStVATDetail;
stPrinterCopy: Array [0..1023] of TStPrinterDataForOneLine;
end;
TStSaleinfo = packed record
ItemType: Byte;
ItemPrice: UInt64;
IncAmount: UInt64;
DecAmount: UInt64;
OrigialItemAmount: UInt32;
OriginalItemAmountCurrency: UInt16;
ItemVatRate: UInt16;
ItemCurrencyType: UInt16;
ItemVatIndex: Byte;
ItemCountPrecision: Byte;
ItemCount: Integer;
ItemUnitType: Byte;
DeptIndex: Byte;
Flag: UInt32;
Name: string;
Barcode: string;
end;
TStPayment = packed record
flags: Byte;
dateOfPayment: UInt32;
typeOfPayment: UInt32; // EPaymentTypes
subtypeOfPayment: Byte; // EPaymentSubtypes
orgAmount: UInt32; // Exp; Currency Amount
orgAmountCurrencyCode: UInt16; // as defined in currecyTable from GIB
payAmount: UInt32;
payAmountCurrencyCode: UInt16;
cashBackAmountInTL: UInt32; // currency with precision 2
cashBackAmountInDoviz: UInt32; // if currency sale, then curency amount
stBankPayment: TStBankPaymentInfo; // Keeps all payment info related with bank
end;
TStBankPaymentInfo = packed record
batchNo: UInt32;
stan: UInt32;
balance: UInt32;
bankBkmId: UInt16;
numberOfdiscount: Byte;
numberOfbonus: Byte;
authorizeCode: string;
transFlag: Array [0..1] of Byte;
terminalId: string;
rrn: string;
merchantId: string;
bankName: string;
numberOfInstallments: Byte;
numberOfsubPayment: Byte;
numberOferrorMessage: Byte;
stBankSubPaymentInfo: Array [0..11] of TStBankSubPaymentInfo;
stCard: TStCardInfo;
stPaymentErrMessage: TStPaymentErrMessage;
end;
TStBankSubPaymentInfo = packed record
My_type: UInt16; // EPaymentSubType
amount: UInt32;
name: string;
end;
TStCardInfo = packed record
inputType: Byte;
pan: string;
holderName: string;
My_type: string;
expireDate: string;
end;
TStPaymentErrMessage = packed record
ErrorCode: string; // bank error code
ErrorMsg: string;
AppErrorCode: string; // payment application specific error code
AppErrorMsg: string;
end;
TStVATDetail = packed record
u32VAT: Integer; //**< Total Tax in TL with precition 2 */
u32Amount: Integer; //**< Total Amount in TL with precition 2 */
u16VATPercentage: UInt16; //**< Tax rate, it is 1800 for %18 */
end;
TStPrinterDataForOneLine = packed record
Flag: UInt32;
lineLen: Byte;
line: string;
end;I am using below code to serialize this records into json:
var
StTicket: TStTicket;
JsonString: RawUTF8;
begin
JsonString := RecordSaveJSON(StTicket, TypeInfo(TStTicket));
end;I have quite a long json string. It's all fine but serialization of "StTaxDetails" defined in TStTicket. What I am having as a serialized json is something like below (beginning and end is cut for making it more readable):
.....":""}}},"stTaxDetails":"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","stPrinterCopy":[{".....What I was expecting is something like:
.....":""}}},"stTaxDetails":[{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0}],"stPrinterCopy":[{".....I am simply stuck at this point. Is it me doing some wrong record declaration(s) here?
Any help is appreciated.
Thanks.
Hi,
There will be two different applications (JAVA and fpc (free pascal compiler)) that will be communicating some information. I am still not very familiar with crypt things. However, I believe mORMot already has what I am searching for.
I need to implement a crypt/decrypt algorithm identical to subject standard.
Is it possible?
Which functions I need to be using?
Thanks.
That did the job perfectly. Thank you.
Hi,
I am mainly using SHA256 for the AES256 cryption. Recently, I needed to control if a file has changed. Size of the file is quite small (~20-30KB) and won't be increasing much. I thought I might save a SHA256 hash of the file somewhere and compare it to monitor "if file has changed"
When I tried to use SynCrypto.SHA256() I realize that it accepts RawByteString as a parameter. I believe, It may be used for file hashing, but I have no idea how to do that.
Is it possible to have an example of SynCrypto.SHA256() used for file hasing?
Thanks.
I tried SynZip already. Need something fast. Compression ratio is not my main concern. Though, even not as much as SynZip, FileSynLZ does compress.
Thanks.
Even I checked, I couldn't find it in documents. One last thing I would like to know about FileSynLZ/FileUnSynLZ is can I deflate a file using some other tool which is compressed using FileSynLZ?
I have already tried 7zip V15.14 and Winrar V5.30 and failed.
I could only find ProDelphi myself.
What other profiler(s) are available free for Delphi 10 which I may try?
I see that function declaration as follows:
function FileSynLZ(const Source, Dest: TFileName; Magic: Cardinal): boolean;I am not sure what value I should provide for parameter "Magic". Is it possible to have an example code, please?
Thanks.
Hi,
I want to fast backup some SQLite database files. Sizes mostly smaller than 2GB. Since it is indicated that lzopas_compressfile is faster than copying files, I wanted to give it a try. Unfortunately, I have found below comment in 1.18.2639 version of the framework in SynLZO unit.
{.$define LZOFILE}
{ attempt to use in-place file compression using memory mapping mechanism
-> still not fully functional -> so do not define }I wonder if the function is not to be used at all.
Thanks.
Hi,
Trying to save as many CPU cycles as possible.
Using OnKeyPress event of a TEdit. Want to Check if Key is 'x' character (case insensitive). CharCase property of the component is ecNormal. Current code is:
if SynCommons.UpperCase(Key) = 'X' then
begin
end;I have checked UpperCase function and it seems to do lots of things inside. I have changed my code as follows:
if Key = 'x' or Key = 'X' then
begin
end;However, I do wonder if there is any code that can be proposed to execute faster.
Thanks.
I could solve my problem as below:
TStTaxRateString = packed record
taxRate: string;
end;
TStTaxRatesString = Array of TStTaxRateString;
TStTaxRateInteger = packed record
taxRate: UInt32;
end;
TStTaxRatesInteger = Array of TStTaxRateInteger;
procedure TfrmMain.btnTaxClick(Sender: TObject);
var
Json: AnsiString;
sRaw:RawUTF8;
RetValTax, RetValDept: TBytes;
RetCode: UInt32;
i, NumberOfTotalTaxRates, NumberOfTotalRecordsReceived: Integer;
Taxes: TStTaxRatesString;
StTaxRates: TStTaxRatesInteger;
begin
SetLength(StTaxRates, 8);
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TStTaxRatesString), 'taxRate word');
// Serialize
Json := AnsiString(DynArraySaveJSON(Taxes, TypeInfo(TStTaxRatesString)));
SetLength(RetValTax, STANDART_BUFFER);
RetCode := Json_FiscalPrinter_GetTaxRates(NumberOfTotalTaxRates, NumberOfTotalRecordsReceived, Json, @RetValTax[0], Length(RetValTax), 8);
if RetCode = 0 then
begin
// Convert TBytes to String which is actually a Json text
s := TEncoding.Default.GetString(RetValTax);
// Manually add " characters at beginning of numbers
sRaw := StringReplaceAll(RawUTF8(s), '":', '":"');
// Manually add " characters at the end of numbers
sRaw := StringReplaceAll(sRaw, '}', '"}');
// Set correct formatting for de-serialization
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TStTaxRatesString), 'taxRate string');
// De-serialization itself
DynArrayLoadJSON(Taxes, Pointer(sRaw), TypeInfo(TStTaxRatesString));
// Copy String Record Type into Integer record type with necessary convertion
for I := 0 to 7 do
StTaxRates[i].taxRate := StrToUInt64(Taxes[i].taxRate);
end;
end;That did not work (function returned nil). Most likely because JSON formatting is a number formatting.
Using version '1.18.2639' of framework, I am getting Access Violation when using DynArrayLoadJSON for a specific record definition.
Record definition which gets access violation:
TStTaxRate = packed record
taxRate: string;
end;
TStTaxRates = Array of TStTaxRate;Below is called at FormCreate:
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TStTaxRate), 'taxRate word');Button click raises exception:
procedure TForm5.Button3Click(Sender: TObject);
var
s: RawUTF8;
stTaxRates: TStTaxRates;
begin
SetLength(stTaxRates, 8);
s := '[{"taxRate":100},{"taxRate":800},{"taxRate":0},{"taxRate":1800},{"taxRate":0},{"taxRate":100},{"taxRate":1800},{"taxRate":800}]';
DynArrayLoadJSON(stTaxRates, Pointer(s), TypeInfo(TStTaxRates));
end;I have another dynamic record which I do not have any problems with.
TStDepartment = packed record
szDeptName: string;
u8TaxIndex: Byte;
iCurrencyType: UInt16;
iUnitType: UInt16;
u64Limit: UInt64;
u64Price: UInt64;
end;
TStDepartments = Array of TStDepartment;
// No TTextWriter.RegisterCustomJSONSerializerFromText() call for this record since it works out of the box
procedure TForm5.Button4Click(Sender: TObject);
var
s: RawUTF8;
stDept: TStDepartments;
begin
SetLength(stDept, 12);
s := '[{"szDeptName":"KSM1","u8TaxIndex":0,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM2","u8TaxIndex":1,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM3","u8TaxIndex":2,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM4","u8TaxIndex":3,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM5","u8TaxIndex":4,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM6","u8TaxIndex":5,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM7","u8TaxIndex":6,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM8","u8TaxIndex":7,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM9","u8TaxIndex":0,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM10","u8TaxIndex":1,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM11","u8TaxIndex":2,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0},{"szDeptName":"KSM12","u8TaxIndex":3,"iCurrencyType":949,"iUnitType":1,"u64Limit":99999999,"u64Price":0}]';
DynArrayLoadJSON(stDept, Pointer(s), TypeInfo(TStDepartments));
end;Sorry, couldn't find it in Documentation "10.1.3.2.4. Text-based definition" section. Is it written somewhere else?
Hi Ab,
That code solved my problem. Thank you. I was starting to afraid that I won't be able to solve it in 1-2 lines of coding before I saw your post.
Should I use it always just before calling DynArraySaveJSON? Or, it is just fine to call once in the application (for example OnCreate event) and that is enough?
My working code is as follows:
TStTaxRate = packed record
taxRate: string;
end;
TStTaxRates = Array of TStTaxRate;
procedure TForm5.Button3Click(Sender: TObject);
var
Json: AnsiString;
stTaxRates: TStTaxRates;
begin
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TStTaxRates), 'taxRate word');
SetLength(stTaxRates, 8);
// Serialize
Json := AnsiString(DynArraySaveJSON(stTaxRates, TypeInfo(TStTaxRates)));
Memo1.Lines.Add('from mORMot: ' + String(Json));
Exit;
end;Memo1 display:
from mORMot: [{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0}]That is exactly what I needed.
Tried another code. This is not working for me, too.
TStTaxRate = record
taxRate: UInt16;
end;
TStTaxRates = Array of TStTaxRate;
procedure TForm5.Button3Click(Sender: TObject);
var
Json: AnsiString;
stTaxRates: TStTaxRates;
begin
SetLength(stTaxRates, 8);
// Serialize
Json := AnsiString(DynArraySaveJSON(stTaxRates, TypeInfo(TStTaxRates)));
Memo1.Lines.Add(String(Json));
Exit;
end;TSTTaxRates is an array type in above code. Result on screen is:
[0,0,0,0,0,0,0,0]This is close to what I need, however still missing variable name in serialized string. How can I change my code to get below result:
[{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0}]Thanks.
I very much appreciate correction of my code, please.
Latest version of the code:
TST_TAX_RATE = record
taxRate: UInt16;
end;
procedure TForm5.Button3Click(Sender: TObject);
var
Json: AnsiString; // DLL call needs me sending AnsiString as parameters
stTaxRates: Array [1..8] of TST_TAX_RATE;
begin
// Serialize
Json := AnsiString(DynArraySaveJSON(stTaxRates, TypeInfo(TST_TAX_RATE), True));
Memo1.Lines.Add(String(Json));
Exit;
end;my result still is
{"taxRate":0}![]()
EDIT: Just downloaded latest nightly build. Result is still same.
Changed related part in my code to:
Json := AnsiString(DynArraySaveJSON(stDept, TypeInfo(TST_DEPARTMENT)));What I received was:
{"taxRate":0}Thanks for your help. Unfortunately, that didn't solve it.
Some points when serializing a class:
5. For nested list/arrays of classes, consider defining T*ObjArray types, register them and use ObjArray*() functions: TSynAutoCreateFields would also recognize such published fields and hold them.
Search for all those TSynPersistent / TSynAutoCreateFields keywords in the documentation.
I have searched documentation. Found part explaining TSynAutoCreateFields. Though, It is beyond my understanding. So, I thought it would be easier for me to provide an example and ask here. Staring with a simpler one since I might get it to my understanding and solve remaining myself.
I have following definitions:
TST_TAX_RATE = record
taxRate: UInt16;
end;And, I need to define that record as an array:
procedure TForm5.Button3Click(Sender: TObject);
var
Json: AnsiString; // DLL call needs me sending AnsiString as parameters
stTaxRates: Array [1..8] of TST_TAX_RATE;
begin
// Serialize
Json := AnsiString(RecordSaveJson(stTaxRates, TypeInfo(TST_TAX_RATE)));
Memo1.Lines.Add(String(Json));
Exit;
end;When I run, above code displays following in Memo1:
{"taxRate":0}What I expect to read in it is something like:
[{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0},{"taxRate":0}]I didn't understand where I am making a mistake here.
Hello,
I tried to read more about how mORMot handles JSON in online documentation. I couldn't find an answer myself. If I have below definitions in my code can I serialize "TStDepartment" class using mORMot json function(s)? Or, Is it better I prepare a record definition of it somehow?
type
TCurrencyType = (
CURRENCY_NONE = 0,
CURRENCY_TL = 949,
CURRENCY_DOLAR = 840,
CURRENCY_EU = 978,
CURRENCY_GPR = 826
);
TItemUnitTypes = (
ITEM_NONE,
ITEM_NUMBER = 1,
ITEM_KILOGRAM = 2,
ITEM_GRAM = 3,
ITEM_LITRE = 4,
// Adetsel Birimler
ITEM_DUZINE = 11,
ITEM_DEMET, // 12
ITEM_KASA, // 13
ITEM_BAG, // 14
// Agirlik Birimler
ITEM_MILIGRAM = 31,
ITEM_TON, // 32
ITEM_ONS, // 33
ITEM_DESIGRAM, // 34
ITEM_SANTIGRAM, // 35
ITEM_POUND, // 36
ITEM_KENTAL, // 37
// Uzunluk Birimler
ITEM_METRE = 51,
ITEM_SANTIMETRE, // 52
ITEM_MILIMETRE, // 53
ITEM_DEKAMETRE, // 54
ITEM_HEKTAMETRE, // 55
ITEM_KILOMETRE, // 56
ITEM_DESIMETRE, // 57
ITEM_MIKRON, // 58
ITEM_INC, // 59
ITEM_FOOT, // 60
ITEM_YARD, // 61
ITEM_MIL, // 62
// Hacim Birimler
ITEM_METREKUP = 71,
ITEM_DESIMETREKUP, // 72
ITEM_SANTIMETREKUP, // 73
ITEM_MILIMETREKUP, // 74
ITEM_DEKALITRE, // 75
ITEM_HEKTOLITRE, // 76
ITEM_KILOLITRE, // 77
ITEM_DESILITRE, // 78
ITEM_SANTILITRE, // 79
ITEM_MILILITRE, // 80
ITEM_INCKUP, // 81
ITEM_GALLON, // 82
ITEM_BUSHEL, // 83
// Alan Birimler
ITEM_METREKARE = 91,
ITEM_DEKAMETREKARE, // 92
ITEM_AR, // 93
ITEM_KILOMETREKARE, // 94
ITEM_DESIMETREKARE, // 95
ITEM_SANTIMETREKARE, // 96
ITEM_MILIMETREKARE, // 97
ITEM_DONUM, // 98
ITEM_HEKTAR, // 99
ITEM_INCKARE // 100
);
TStDepartment = class
private
FDeptName: string;
FU8TaxIndex: Byte;
FCurrencyType: TCurrencyType;
FUnitType: TItemUnitTypes;
FU64Limit: UInt64;
FU64Price: UInt64;
public
constructor Create();
public
property DeptName: string read FDeptName write FDeptName;
property U8TaxIndex: Byte read FU8TaxIndex write FU8TaxIndex;
property CurrencyType: TCurrencyType read FCurrencyType write FCurrencyType;
property UnitType: TItemUnitTypes read FUnitType write FUnitType;
property U64Limit: UInt64 read FU64Limit write FU64Limit;
property U64Price: UInt64 read FU64Price write FU64Price;
end;
{ TStDepartment }
constructor TStDepartment.Create;
begin
FDeptName := '';
end;I might not understood your proposition. I tried to define my record variables as TBytes and resulting json was not what I have posed in #4 in this thread.
It is quite customized json format DLL requires. Otherwise, I am getting "json format error" as a result from function calls. Some of the variables are first converted to hex before converting them to Base64. Those are mainly numbers as far as I can see.
I believe, I got it to work now. Code is as below. Tests seems to be working OK. Had to convert everything to AnsiString since that is what DLL requests.
There is this one thing I would like to get some suggestions though. Is there any faster function in mORMot to replace "TNetEncoding.Base64.EncodeBytesToString()" ?
Thanks.
// DLL import definitions
procedure GetErrorMessage(ErrorCode: UInt32; Buffer: TBytes); cdecl; external 'GMPSmartDLL.dll';
function Json_FiscalPrinter_Echo(szEcho_Out: TBytes; EchoLen_Out, TimeoutInMiliseconds:integer): UInt32; cdecl; external 'GMPSmartDLL.dll';
function Json_GMP_StartPairingInit(szPairing: AnsiString; var szPairingResp: TBytes; PairingRespLen: Integer): Uint32; cdecl; external 'GMPSmartDLL.dll';
type
TST_GMP_PAIR = packed record
In_ProcOrderNum : AnsiString;
In_ProcDate : AnsiString;
In_ProcTime : AnsiString;
In_DeviceBrand : AnsiString;
In_DeviceModel : AnsiString;
In_DeviceSerialNum : AnsiString;
In_DeviceEcrRegisterNo : AnsiString;
end;
function TForm5.AscToBcd(const Value: string): TBytes;
begin
if Length(Value) > 32 then
begin
// because static buffers are the best, we fail like the original code
end else
begin
SetLength(Result, 16);
HexToBin(PChar(Value), Result, Length(Result));
end;
end;
procedure TForm5.btnPairClick(Sender: TObject);
var
i:Integer;
sent:TST_GMP_PAIR;
//recv:TST_GMP_PAIR_RESP;
s,json:AnsiString;
pResp,b:TBytes;
begin
// Fill record structure.
sent.In_ProcOrderNum := AnsiString(TNetEncoding.Base64.EncodeBytesToString(Copy(AscToBcd('000001'), 0, 16)));
sent.In_ProcDate := AnsiString(TNetEncoding.Base64.EncodeBytesToString(Copy(AscToBcd(FormatDateTime('ddmmyy', Now)), 0, 3)));
sent.In_ProcTime := AnsiString(TNetEncoding.Base64.EncodeBytesToString(Copy(AscToBcd(FormatDateTime('hhmmss', Now)), 0, 3)));
sent.In_DeviceBrand := AnsiString(TNetEncoding.Base64.EncodeBytesToString(TEncoding.ASCII.GetBytes('INGENICO')));
sent.In_DeviceModel := AnsiString(TNetEncoding.Base64.EncodeBytesToString(TEncoding.ASCII.GetBytes('IWE280')));
sent.In_DeviceSerialNum := AnsiString(TNetEncoding.Base64.EncodeBytesToString(TEncoding.ASCII.GetBytes('JHWE20000079')));
sent.In_DeviceEcrRegisterNo := AnsiString(TNetEncoding.Base64.EncodeBytesToString(TEncoding.ASCII.GetBytes('12344567')));
json := AnsiString(RecordSaveJSON(sent, TypeInfo(TST_GMP_PAIR)));
Memo1.Lines.Add(EmptyStr);
Memo1.Lines.Add('New Code Produced JSON:');
Memo1.Lines.Add(string(json));
SetLength(pResp, 200000);
i := Json_GMP_StartPairingInit(json, pResp, Length(pResp));
if i <> 0 then begin
SetLength(b, 1000);
GetErrorMessage(i, b);
s := AnsiString(TEncoding.ASCII.GetString(b));
Memo1.Lines.Add(EmptyStr);
Memo1.Lines.Add('ERROR: ' + String(s));
end else begin
Memo1.Lines.Add(EmptyStr);
Memo1.Lines.Add('Pairing: OK.');
end;
end;Thanks for all suggestions. I have one more question. When I use RecordSaveJSON on byte variables. Does it automatically convert it into Base64 string?
I was wrong. I could get a detail of "szJsonPairing" that is as follows:
C# Code for setting parameters for DLL call:
ST_GMP_PAIR pairing = new ST_GMP_PAIR();
pairing.In_DeviceBrand = Encoding.Default.GetBytes("INGENICO");
pairing.In_DeviceModel = Encoding.Default.GetBytes("IWE280");
pairing.In_DeviceEcrRegisterNo = Encoding.Default.GetBytes("12344567");
pairing.In_DeviceSerialNum = Encoding.Default.GetBytes("JHWE20000079");
pairing.In_ProcOrderNum = parsClass.GMP_AscToBcd("000001");
Array.Copy(parsClass.GMP_AscToBcd(m_lblProcDate.Text.Substring(0, 2) + m_lblProcDate.Text.Substring(3, 2) + m_lblProcDate.Text.Substring(6, 2)), pairing.In_ProcDate, pairing.In_ProcDate.Length);
Array.Copy(parsClass.GMP_AscToBcd(m_lblProcTime.Text.Substring(0, 2) + m_lblProcTime.Text.Substring(3, 2) + m_lblProcTime.Text.Substring(6, 2)), pairing.In_ProcTime, pairing.In_ProcTime.Length);
ST_GMP_PAIR_RESP pairingResp = new ST_GMP_PAIR_RESP();
resp = Json_GMPSmartDLL.GMP_StartPairingInit(ref pairing, ref pairingResp);C# function making DLL call itself:
public static UInt32 GMP_StartPairingInit(ref ST_GMP_PAIR pStPair, ref ST_GMP_PAIR_RESP pStPairResp, int TimeoutInMiliseconds = Defines.TIMEOUT_ECHO)
{
string szJsonPairing = JsonConvert.SerializeObject(pStPair);
byte[] szJsonPairing_Out = new byte[Defines.GMP_TICKET_BUFFER];
UInt32 retcode = Json_GMP_StartPairingInit(szJsonPairing, szJsonPairing_Out, szJsonPairing_Out.Length);
if (retcode == 0)
{
string retJsonString = GMP_Tools.SetEncoding(szJsonPairing_Out);
pStPairResp = JsonConvert.DeserializeObject<ST_GMP_PAIR_RESP>(retJsonString);
}
return retcode;
}Value of "szJsonPairing" after it is Serialized in DLL call function:
{"In_ProcOrderNum":"AAABAAAAAAAAAAAAAAAAAA==","In_ProcDate":"JwQW","In_ProcTime":"IEYg","In_DeviceBrand":"SU5HRU5JQ08=","In_DeviceModel":"SVdFMjgw","In_DeviceSerialNum":"SkhXRTIwMDAwMDc5","In_DeviceEcrRegisterNo":"MTIzNDQ1Njc="}Since I have the hardware with me and Visual Studio installed some other city, I won't be able to get details of "szJsonPairing_Out" for about 2 weeks I assume.
I've found out that C# application uses "Newtonsoft.Json.7.0.1" for converting Json to and from. Which seems to be a open source .NET framework.
http://www.newtonsoft.com/json
I think this is as far as I can get to the Json details of C# application.
Hi,
I have very low to no knowledge of JSON. So, I maybe asking my question wrongly here. Hope it will be understandable.
There is this C# application with code available to me which uses a C# DLL. Application is communicating with a POS device using that DLL.
I am writing a Delphi application which uses that same C# DLL. I see that at some point C# application using JsonConvert.SerializeObject() and JsonConvert.DeserializeObject() functions, when I check the code. Sample lines from C# code is as follows:
public static UInt32 GMP_StartPairingInit(ref ST_GMP_PAIR pStPair, ref ST_GMP_PAIR_RESP pStPairResp, int TimeoutInMiliseconds = Defines.TIMEOUT_ECHO)
{
string szJsonPairing = JsonConvert.SerializeObject(pStPair);
byte[] szJsonPairing_Out = new byte[Defines.GMP_TICKET_BUFFER];
UInt32 retcode = Json_GMP_StartPairingInit(szJsonPairing, szJsonPairing_Out, szJsonPairing_Out.Length);
if (retcode == 0)
{
string retJsonString = GMP_Tools.SetEncoding(szJsonPairing_Out);
pStPairResp = JsonConvert.DeserializeObject<ST_GMP_PAIR_RESP>(retJsonString);
}
return retcode;
}I do not know how to do that on Delphi. I have no sample data sent/received. I just know that mORMot project has JSON routines. So, I appreciate if someone can help me out.
Record structure to Serialize at Delphi:
ST_GMP_PAIR : record
In_ProcOrderNum : array [0..3] of Byte;
In_ProcDate : array [0..3] of Byte;
In_ProcTime : array [0..3] of Byte;
In_DeviceBrand : array [0..16] of Byte;
In_DeviceModel : array [0..16] of Byte;
In_DeviceSerialNum : array [0..16] of Byte;
In_DeviceEcrRegisterNo : array [0..17] of Byte;
end;Record structure to DeSerialize at Delphi:
ST_GMP_PAIR_RESP: record
Out_ProcOrderNum : array[0..6] of Byte;
Out_ProcDate : array[0..6] of Byte;
Out_ProcTime : array[0..6] of Byte;
Out_DeviceBrand : array[0..16] of Byte;
Out_DeviceModel : array[0..16] of Byte;
Out_DeviceSerialNum : array[0..16] of Byte;
Out_ErrorRespCode : array[0..2] of Byte;
Out_StatusCode : array[0..2] of Byte;
Out_VersionNumber : array[0..8] of Byte;
end;Thanks.
I do need AES256-SHA for WinCE. I will try what Marius suggested to see if that helps.
Marius, you say that you can compile SnyCrypto under Lazarus for wince-arm, is it possible you pass that file to me for testing? I do have platform to make tests. I also use "SynCommons.HexToBin", "SynCommons.StringToUTF8", and "SynCommons.BinToBase64" in my code. If these are not present in your modified SynCrypto, you may want to send me some code to do actual test together with the SynCrypto file.
Hi Marius,
I have tried your suggestion already. First I thought there will be slight changes and changes will be just at the beginning of file. I was wrong. Unfortunately, {$ifdef}, {$ifndef} and {$else} are all over it. Moreover, file has 55000 lines of code which I am completely not familiar with. I got lost, and converted everything back to default.
What I need is basically what SynCrypto file needs. However, I am lost trying to figure definitions, functions, etc. necessary to identify, too.
Hi,
We all know that constants and strings written directly in source code are also directly written in compiled EXE files. So, someone trying to hack the key may go in assembly code, see some strings there & may search EXE file with a hex editor and also might extract my fixed string for reversing crypt text.
I wonder if there are some easy ways to "hide" my key used for AES256 encryption in compiled EXE file.
Thanks.
--Ertan
Hi,
My framework version is: 1.18.2458. When I include SynCommons.pas in my uses in Lazarus targeting WinCE platform with ARM cpu I get following error:
SynCommons.pas(765,3) Fatal: Cannot find BaseUnix used by SynCommons.
Is there any workaround I might do to get it compiled? All I need is SynCommons and SyncCrypt to compile with above configuration, not the complete framework.
Thanks.
--Ertan
It turns out that I installed version 1.17 of the framework which is indicated as stable on the web site. When I switch to version 1.18 nightly build from 2016-03-15 I got IVAtBeginning as a parameter for EncryptPKCS7 and DecryptPKCS7 functions.
Now, I can encrypt, and decrypt.
My final code is as follows:
const
my_key = 'testkey';
var
Form10: TForm10;
implementation
{$R *.dfm}
uses SynCommons, SynCrypto;
procedure TForm10.btnMakeAESClick(Sender: TObject);
var
key : TSHA256Digest;
aes : TAESCFB;
s:RawByteString;
begin
SynCommons.HexToBin(Pointer(SHA256(my_key)), @key, 32);
aes := TAESCFB.Create(key, 256);
try
s := StringToUTF8(edtTextToEncrypt.Text);
s := BinToBase64(aes.EncryptPKCS7(s, True));
edtCrypted.Text := UTF8ToString(s);
finally
aes.Free;
end;
end;
procedure TForm10.btnDecryptAESClick(Sender: TObject);
var
key : TSHA256Digest;
aes : TAESCFB;
s:RawByteString;
begin
SynCommons.HexToBin(Pointer(SHA256(my_key)), @key, 32);
aes := TAESCFB.Create(key, 256);
try
s := StringToUTF8(edtCrypted.Text);
s := aes.DecryptPKCS7(Base64ToBin(s), True);
edtDecrypted.Text := UTF8ToString(s);
finally
aes.Free;
end;
end;Now, I have different crypt strings for same text.
Text to crypt: 'Sample Text at all!'
Crypt text1: 'WcSmQUMs0yPMPEwaaseNCWThhFkNzSEifnn0631q3c6IfKnurWHxjxtNliCcTBBL'
Crypt text2 (clicked btnMakeAES again): 'ioFKOtLfMFxXATJ4oiQw5P5gXUExvGBssiWtlgeDoNMkIBpka2Y7eo8KuYo8n/MA'
Crypt text3 (clicked btnMakeAES 3rd time): 'Yb8aMYICC51nbynZ6DLG1CmtCPui8HD9vUQgtnDg5o/p0DywyrVDbaIOhnOSIS7n'
All above Crypt strings decrypt back to 'Sample Text at all!' which is good.
Now, I wonder if there is anything more I can do to make crypt strings stronger than they are now.
Thanks for all the support.
--Ertan
Or even better, do not create a manual fixed IV, but use the IVAtBeginning=true parameter to EncryptPKCS7/DecryptPKCS7 methods, which would create a random IV for each encryption.
I believe I could do all suggestions but above one. SynCommons.pas or SynCrypto.pas do not have "IVAtBeginning" text in it. I couldn't find this parameter declared anywhere at all. Would you explain a little bit more, please? Maybe with some code sample?
--Ertan
After some more search on the forum I found this post: http://synopse.info/forum/viewtopic.php?id=1587
Thank you Swanty!
I have used it and below is the code that I came up with.
uses SynCommons, SynCrypto;
procedure TForm10.btnMakeAESClick(Sender: TObject);
const
my_key = 'testkey';
my_iv = '1234567890ABCDEF';
var
key : TSHA256Digest;
aes : TAESCBC;
iv : TAESBlock;
begin
HexToBin(Pointer(SHA256(my_key)), @key, 32);
Move(TEncoding.ANSI.GetBytes(my_iv)[0], iv[0], 16);
aes := TAESCBC.Create(key, 256, iv);
try
edtCrypted.Text := BinToBase64(aes.EncryptPKCS7(edtTextToEncrypt.Text));
finally
aes.Free;
end;
end;
procedure TForm10.btnDecryptAESClick(Sender: TObject);
const
my_key = 'testkey';
my_iv = '1234567890ABCDEF';
var
key : TSHA256Digest;
aes : TAESCBC;
iv : TAESBlock;
begin
HexToBin(Pointer(SHA256(my_key)), @key, 32);
Move(TEncoding.ANSI.GetBytes(my_iv)[0], iv[0], 16);
aes := TAESCBC.Create(key, 256, iv);
try
edtDecrypted.Text := aes.DecryptPKCS7(Base64ToBin(edtCrypted.Text));
finally
aes.Free;
end;
end;edtTextToEncrypt.Text = 'Sample Text at all!'
edtCrypted.Text = 'Occ1u4nfrXSaJUZvbXCg1zpSytS4vFH4sldaZjU46gQ='
edtDecrypted.Text = 'Sample Text at all!'
So, could I do an AES crypt text with above code? Or, this is a crypt text but not an AES crypt because it uses "PKCS7"? Just give it to me being newbie, please.
Length('Sample Text at all!') = 20 ?
I read below in SynCrypto.pas:
TAESBlock = packed array[0..AESBlockSize-1] of byte;
AESBlockSize = 16
I didn't understand how to fit for example 20 characters into 16 bytes. Or, 60 characters into 16 bytes.
Well, I tried to explain that I do not know cryptography and how to use it. I do need a sample to understand, please.
Hi,
I am all new to this encryption stuff. I am suggested to use AES anyway. So here I am.
My code below is not working as I expected, and I couldn't find any other sample I can use of. So, I appreciate someone fix it for me, please.
uses SynCrypto;
procedure TForm10.Button1Click(Sender: TObject);
var
myAES:TAES;
myBlock:TAESBlock;
I: Integer;
s:string;
begin
myAES.EncryptInit('12345678901234567890123456789012', 256);
for I := 1 to 16 do begin
myBlock[i-1] := Ord(edtTextToEncrypt.Text[i]);
end;
myAES.Encrypt(myBlock);
// Fill with zeros
s := '0000000000000000'; // 16 character string
for I := 1 to 16 do begin
s[i] := Chr(myBlock[i-1]);
end;
edtCrypted.Text := s;
end;
procedure TForm10.Button2Click(Sender: TObject);
var
myAES:TAES;
myBlock:TAESBlock;
I: Integer;
s:string;
begin
myAES.DecryptInit('12345678901234567890123456789012', 256);
for I := 1 to 16 do begin
myBlock[i-1] := Ord(edtCrypted.Text[i]);
end;
myAES.Decrypt(myBlock);
// Fill with zeros
s := '0000000000000000'; // 16 character string
for I := 1 to 16 do begin
s[i] := Chr(myBlock[i-1]);
end;
edtDecrypted.Text := s;
end;Text to encrypt is: Sample Text at all!
Decrypted text is: Sample Text at a
Thanks.