I am having trouble getting the same encrypted values returned between Delphi and Oracle any assistance would be greatly appreciated.
It could possibly be the padding that might be causing the difference, unfortunately I am not sure.
Lockbox 3
Delphi RAD Studio Tokyo 10.2
//uses uTPLb_Constants,uTPLb_BaseNonVisualComponent, uTPLb_Codec, uTPLb_CryptographicLibrary, IdHashMessageDigest, idHash
var cipher64, CipherText : string;
plainText: utf8string;
keyText: utf8string;
FLibrary: TCryptographicLibrary;
FCodec: TCodec;
bytes, cipher: TBytes;
workHash : TIdHashMessageDigest5;
Result : String;
begin
plainText := 'test-data';
keyText := 'test_key';
try
workHash := TIdHashMessageDigest5.Create;
Result := workHash.HashStringAsHex(keyText);
finally
FreeAndNil(workHash);
end;
memoOutput.Lines.Add('plaintext = ' + plainText);
memoOutput.Lines.Add('key hash = ' + Result);
FLibrary := TCryptographicLibrary.Create(Self);
try
FCodec := TCodec.Create(Self);
try
FCodec.CryptoLibrary := FLibrary;
FCodec.StreamCipherId := BlockCipher_ProgId;
FCodec.BlockCipherId := Format(AES_ProgId, [128]);
FCodec.ChainModeId := ECB_ProgId;
FCodec.password := Result;
FCodec.EncryptString( plainText, CipherText, Tencoding.UTF8 );
FCodec.Burn;
finally
FCodec.Free;
end;
finally
FLibrary.Free;
end;
Results :
key hash = 8C32D1183251DF9828F929B935AE0419 MD5 Hash of text "test_key"
ciphertext = FJRXv9zMbypUmYnzzEHLnA== Base64 Result from Lockbox
Oracle XE
declare
raw_key raw(200);
encryption_type number;
encrypted_result varchar2(4000);
decrypted_result varchar2(4000);
begin
raw_key := DBMS_CRYPTO.Hash (UTL_I18N.STRING_TO_RAW ('test_key', 'AL32UTF8'), DBMS_CRYPTO.HASH_MD5);
-- Initialize the encrypted result
encryption_type:= DBMS_CRYPTO.ENCRYPT_AES128 + DBMS_CRYPTO.CHAIN_ECB + DBMS_CRYPTO.PAD_PKCS5;
-- Then the data is being encrypted with AES:
encrypted_result := DBMS_CRYPTO.ENCRYPT(UTL_I18N.STRING_TO_RAW('test-data', 'AL32UTF8'), encryption_type, raw_key);
decrypted_result := DBMS_CRYPTO.DECRYPT(encrypted_result, encryption_type, raw_key);
dbms_output.put_line(raw_key);
dbms_output.put_line(encrypted_result);
dbms_output.put_line(UTL_RAW.CAST_TO_VARCHAR2 (decrypted_result));
dbms_output.put_line(utl_raw.cast_to_varchar2(utl_encode.BASE64_ENCODE(encrypted_result)));
end;
Results :
Key Hash : 8C32D1183251DF9828F929B935AE0419
Encrypt : 8FCA326C25C8908446D28884394F2E22 Hex value returned
Base 64 : j8oybCXIkIRG0oiEOU8uIg==
Yes, Lockbox is using Ciphertext stealing for the padding. Your Oracle code is using PKCS5 padding.
Related
OpenResty lua-resty-string: Unable to decrypt data which can be decrypted by Golang and Python
https://github.com/openresty/lua-resty-string
I can decrypt data with enc, key, iv like:
test_enc:"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"
test_key:="4AvVhmFLUs0KTA3Kprsdag=="
test_iv:="vN2mBu17W/8Ewfg3AX8Ayg=="
by Golang and Python:
Golang Code:
func decodeAesGcmTest() {
test_enc := "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"
test_key := "4AvVhmFLUs0KTA3Kprsdag=="
test_iv := "vN2mBu17W/8Ewfg3AX8Ayg=="
key, _ := base64.StdEncoding.DecodeString(test_key)
byteKey := []byte(key)
add := []byte("")
block, _ := aes.NewCipher(byteKey)
aesgcm, _ := cipher.NewGCMWithNonceSize(block, 16)
iv, _ := base64.StdEncoding.DecodeString(test_iv)
enc, _ := base64.StdEncoding.DecodeString(test_enc)
plaintest, _ := aesgcm.Open(nil, iv, enc, add)
fmt.Println("plaintest: ", string(plaintest))
}
Python Code:
def test_gcm_decode():
test_enc = "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"
test_key = "4AvVhmFLUs0KTA3Kprsdag=="
test_iv = "vN2mBu17W/8Ewfg3AX8Ayg=="
enc = base64.b64decode(test_enc)
key = base64.b64decode(test_key)
iv = base64.b64decode(test_iv)
mode = AES.MODE_GCM
decryptor = AES.new(key, mode, iv)
plaintext = decryptor.decrypt(enc)
print(plaintext)
but I cannot decrypt it with lua-resty-string:
local function gcm_decrypt()
local aes = require "resty.aes"
local ngx_decode_base64 = ngx.decode_base64
local cipher_len = {
128,
192,
256
}
local test_enc = "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"
local test_key = "4AvVhmFLUs0KTA3Kprsdag=="
local test_iv = "vN2mBu17W/8Ewfg3AX8Ayg=="
local enc = ngx_decode_base64(test_enc)
local key = ngx_decode_base64(test_key)
local iv = ngx_decode_base64(test_iv)
for _, vv in ipairs(cipher_len) do
local decryptor, err = aes:new(key, nil, aes.cipher(vv, "gcm"), {iv = iv}, nil, nil, false)
if decryptor then
local plaintext, err = decryptor:decrypt(enc)
if not err and plaintext then
return true
else
ngx.log(ngx.ERR, "decrypt failed: ", err)
end
else
ngx.log(ngx.ERR, "aes new failed: ", err)
end
end
end
Is the method I am using is wrong?
Thank you~
I try to decrypt with enc, key, iv using Golang and Python.
I want to decrypt with enc, key, iv using lua-resty-string but failed.
In lua-resty-string, the :decrypt(ciphertext, tag = nil) method expects an authentication tag passed as a separate parameter: https://github.com/openresty/lua-resty-string/blob/v0.15/lib/resty/aes.lua#L270
Conversely, the Golang/Python libraries you've used expect an authentication tag appended to a ciphertext
Check this question for futher explanation:
The authentication tag is defined as an output parameter in GCM (see section 7, step 7 of NIST SP 800-38D). In all the API's I've encountered it's appended to the ciphertext.
RFC 5116, section 5.1, AEAD_AES_128_GCM:
An authentication tag with a length of 16 octets (128
bits) is used. The AEAD_AES_128_GCM ciphertext is formed by
appending the authentication tag provided as an output to the GCM
encryption operation to the ciphertext that is output by that
operation.
A real life example (Python cryptography library): https://github.com/pyca/cryptography/blob/39.0.0/src/cryptography/hazmat/backends/openssl/aead.py#L259-L267
This is a fix for your OpenResty code:
-- "An authentication tag with a length of 16 octets (128 bits) is used"
local tag_len = 16
-- enc_data = enc[:-16], enc_tag = enc[-16:]
local enc_data = enc:sub(1, -(tag_len + 1))
local enc_tag = enc:sub(-tag_len)
decryptor:decrypt(enc_data, enc_tag)
I´m using a Dahua Facial terminal and it has a API like (CGI style) and a SDK. i asked some questions about dll convertions, but now i´m trying to use de API too.
The API to monitoring the events handled by Facial is
http://192.168.1.201/cgi-bin/snapManager.cgi?action=attachFileProc&Flags[0]=Event&Events=[AccessControl]
Is a multipart/x-mixed-replace response how return a first bondary as text/plain with the event data and a bondary with a image/jpeg with the snapshot of the event.
Using the info online about Indy and some useful posts made by Lebeau i cad read the text data using idHttp.IoHanlder.ReadLn(IndyTextEncoding_UTF8)
I tryed to read the next bondary (image) with idHttp.IOHandler.ReadByte, ReadBytes, ReadStream but not sucess.
Here is the response using idHttp.IoHandler.ReadLn
--myboundary
Content-Type: text/plain
Content-Length: 1035
Events[0].Alive=100
Events[0].CardName=Joao Test
Events[0].CardNo=0B8748EB
Events[0].CardType=0
Events[0].CreateTime=1616297700
Events[0].Door=0
Events[0].ErrorCode=0
Events[0].Method=15
Events[0].ReaderID=1
Events[0].Similarity=99
Events[0].SnapPath=/var/tmp/partsnap96.jpg
Events[0].Status=1
Events[0].Type=Entry
Events[0].UTC=1616297700
Events[0].UserID=1
Events[0].UserType=0
--myboundary
Content-Type: image/jpeg
Content-Length: 54235
����
(1#%(:3=<9387#H\N#DWE78PmQW_bghg>Mqypdx\egc//cB8Bcccccccccccccccccccccccccccccccccccccccccccccccccc//cB8Bcccccccccccccccccccccccccccccccccccccccccccccccccc��
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������������������������������������������������������������������������
$4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz��������������������������������������������������������������������������
�XQz �?m�c$[J��5"�Hz�~5���m+��b{�����{��n��*p�p*�8�bx��
`3mjLQ��9CB���T���D���'ޥAY\ų���>�*��c�U���h�R�%��je�W��*]�m�p��m?��c6�?��b��R��1N�.(��.)إ�
u\,8�
)�ny�ڌү
#
#��
L�rɳ���B�Ns�� S�K��
�i�F��Z�af�
������ޭ�T�
/l�i]Q��l������
C�RS�
ʛO^�ҫ���
h�
P)#�
pN��
\S���0�1K�
f2N�⫑S�-�LF-�Y�8?0��.�?[�nE[��t[��s�w�h��_���y�[�R�*��=je ������4�M��,?�x��Ƣ�Sל�t8�F�
ZJZ
(��R�E
)h�bR�K#����
p�S����)تb���x1�O��(��i�1����5��r=i��i�B�A��J�{���ںT5s��_��
Q#-�
Z1J
x�i�i�S�NU��
�Kf=9=Pƺ�s�ٿ��N����uS�Tj��#��d��-N-����gw�W5�0*z0��=&m��=T��S�����
x�`JpJxZpZ"��i
p���#
<S7
P���R�a�wP"���� %!�Q�
��`�M�6��wⵍfjJb�I�������{�h/���ڞ�r�Q��Ta�ϫ�7E��o�����5%���X��C�
�v�G�rO���
��徸�(�O�T�4�4��ц��j8�
��3sM�X�'�G��ڪξ\�/L|��i����I?+|�Z�
�?��K[M��L7�^
K�#d�Hb��q߯�V�'|a��C�E�Z�+�
f�&����`'�ϑ��E�r>�Ƶ'Q�7~��<r}��XT�+������pHQۭ
I´m creating a class to implement the API and SDK, in this case (API) to manage the events i wrote a thread class to consume the Event API and syncronize the data when a event occur, the idHttp is owned by the thread class and it inside a TDispositivo class, so i run one thread class for each TDispositivo included on main class.
Here is the Execute code from the thread. (ignoring the image data because i do not now how to get it rigth.
procedure TMonitor.Execute;
var
Ret, URL, Chave, Valor : String;
I, isInteger : Integer;
Concluido : boolean;
Tentativas: Integer;
begin
Tentativas := 3;
fAtivo := True;
FContador := 0; //zerando contador
//executa enquanto fAtivo for True e terminated for False
while fAtivo and not self.Terminated do
begin
if fOwner.alive then
begin
//preparando URL
With fOwner.Config do
begin
Url := 'http://'+ IP + ifthen(PortaWeb>=0,':'+PortaWeb.ToString,'')+'/cgi-bin/snapManager.cgi?action=attachFileProc&Flags[0]=Event&Events=[AccessControl]';
end;
//Incrementando contado
Inc(fContador);
//Efetuando o GET dentro de um try except para evitar interrupcao na thread
Try
ret := fHttp.Get(Url);
except
End;
fOwner.doGet(fhttp.ResponseCode, fhttp.ResponseText);
//tratando erros http
if fHttp.ResponseCode <> 200 then
begin
case fHttp.ResponseCode of
400: Erro(740,'Chamada ao terminal mal formada');
401: Erro(741,'Chamada ao terminal não autorizada');
403: Erro(743,'Recurso do servidor proibido');
404: Erro(744,'Recurso do terminal não encontrado');
500: Erro(750,'Erro interno no processamento de chamadas do terminal');
501: Erro(751,'Recurso do terminal não implementado');
end;
if (fContador >= Tentativas) then
begin
Erro(700,'Falha ao conectar o dispositivo. Número de tentativas excedido');
fContador := 0;
//verificando se vai continuar tentando se reconectar
if fOwner.Config.Reconectar then
begin
Log('Aguardando para tentar reconectar o monitor ...');
Sleep(fOwner.Config.TempoEsperaReconectar);
end
else
begin
Log('Finalizando monitoramento por falha de comunicação');
Self.Stop;
end;
end;
end
else
begin
//zerando contador após uma conexão bem sucedida;
FContador := 0;
//para evitar final do chunk ou close gracefully
try
if IsHeaderMediaType(fHttp.Response.ContentType, 'multipart') then
begin
i := 0;
Concluido := False;
repeat
if (i >= 35) Or Concluido then
begin
//tirando snap antes de processar o evento para ver se diminui o delay
if FOwner.Config.SnapshotEvento then
fOwner.getSnapshot;
Synchronize(Evento);
Concluido := False;
i := 0;
end;
fLinha := fHttp.IOHandler.ReadLn(IndyTextEncoding_UTF8);
if Pos('Content-Length', fLinha) > 0 then
begin
i := 0;
Concluido := False;
fEvento.Limpar;
end
Else if Pos('Events[', fLinha) > 0 then
begin
if fOwner.Config.Depurar then
Log(fLinha);
Inc(I);
Chave := Trim(retPar(1,'=',retPar(2,'.',fLinha)));
Valor := Trim(retPar(2,'=',fLinha));
if Valor = '' then
Valor := '0';
With fEvento do
begin
if Chave = 'Alive' then
Alive := ifthen(Valor = '',0,Valor.ToInteger)
else if Chave = 'CardName' then
CardName := ifthen(Trim(Valor) = '0','Não identificado',trim(Valor))
else if Chave = 'CardNo' then
begin
if TryStrToInt(Valor, isInteger) then
CardNo := ifthen(Valor = '', '-1', Valor)
else
CardNo := WiegandHexToInt(Valor).ToString;
end
else if Chave = 'CardType' then
CardType := ifthen(Valor = '', -1, Valor.ToInteger)
else if Chave = 'CreateTime' then
CreateTime := UnixToDateTime(Valor.ToInt64, False)
else if Chave = 'Door' then
Door := ifThen(Valor = '',-1, Valor.ToInteger)
else if Chave = 'ErrorCode' then
ErrorCode := ifThen(Valor = '',-1, Valor.ToInteger)
else if Chave = 'EventBaseInfo.Action' then
EventBaseAction := Valor
else if Chave = 'EventBaseInfo.Code' then
EventBaseCode := Valor
else if Chave = 'EventBaseInfo.Index' then
EventBaseIndex := ifThen(Valor = '',-1, Valor.ToInteger)
else if Chave = 'Method' then
Metodo := ifThen(Valor = '',-1, Valor.ToInteger)
else if Chave = 'ReaderID' then
LeitorID := ifThen(Valor = '',-1, Valor.ToInteger)
else if Chave = 'Similarity' then
Similaridade := ifthen(Valor = '', 0, Valor.ToInteger)
else if Chave = 'SnapPath' then
snappath := Valor
else if Chave = 'Status' then
Status := ifthen(Valor = '', -1, Valor.ToInteger)
else if Chave = '.Type' then
TipoAcesso := Valor
else if Chave = 'UTC' then
DataHora := UnixToDateTime(Valor.ToInt64, False)
else if Chave = 'UserID' then
UserID := ifthen(Valor = '', -1, Valor.ToInteger)
else if Chave = 'UserType' then
begin
i := 34;
Concluido := True;
UserType := ifthen(Valor = '', -1, Valor.ToInteger);
end;
end;
end;
until fhttp.IOHandler.ClosedGracefully;
end;
except
end;
end;
inherited;
end
else
begin
//dispositivo não respondeu ao ping
//verificando se vai continuar tentando se reconectar
if fOwner.Config.Reconectar then
begin
Log('Aguardando para tentar reconectar o monitor ...');
Sleep(fOwner.Config.TempoEsperaReconectar);
end
else
begin
Log('Finalizando monitoramento por falha de comunicação');
Self.Stop;
end;
inherited;
end;
end;
//rotina de finalização da thread
if FHttp.Connected then
begin
try
Fhttp.Disconnect;
except
end;
end;
end;
First question, Can i do it ? Indy can do It ? Any suggestions ?
Second question, I observe the loop to retrive data when GET is running raise a Close gracefully when i try to readLn after the data is end. In Firefox the GET still running after the image and still working, in my case, the GET is finished and the threand.execute call GET again.
Is possible to keep the GET running avoiding premature interruption and processes the new data when present ?
EDIT: When this part of the code run, the line NewDecoder := TIdMessageDecoderMIME(Decoder).ReadBody(BodyStream, MsgEnd); raises a close gracefully, looking deeper on Indy code i found a TIOHandler.ReadLn how execute CheckForDisconnect(True,True) when LTerm = -1 and this break the execution without retrive the last bytes of data.
Thinking about this i´m suspect has a rellation with the Responde.KeepAlive is always False ans the Connection content is always close it´s explain why Decoder.Readybody raises a Close gracefully and break my execution.
But, if i run the api call on eg. Firefox, the connection still running after the FF get the image and only interrupts whenreachs a timeout.
Is it possible something on headers sended by terminal ? or the way how idHttp parse the headers data ?
//part of code after http.get
mcptAttachment: begin
BodyStream := TMemoryStream.Create;
try
BodyStream.Position := 0;
NewDecoder := TIdMessageDecoderMIME(Decoder).ReadBody(BodyStream, MsgEnd); //<-- here comes a close gracefully
jpg := TJPEGImage.Create;
try
BodyStream.Position := 0;
jpg.LoadFromStream(BodyStream);
jpg.SaveToFile('C:\Producao\API_SDK\Facial\teste.jpg');
finally
jpg.Free;
Decoder.Free;
Decoder := NewDecoder;
end;
finally
BodyStream.Free;
end;
end;
//part of the code of tIOHandler.ReadLn
// ReadFromSource blocks - do not call unless we need to
else if LTermPos = -1 then begin
// ReadLn needs to call this as data may exist in the buffer, but no EOL yet disconnected
CheckForDisconnect(True,True); //The execution stops here whiout return the last bytes and premature finishing the code above with a close gracefully
// Can only return -1 if timeout
FReadLnTimedOut := ReadFromSource(True, ATimeout, False) = -1;
if (not FReadLnTimedOut) and (ATimeout >= 0) then begin
if GetElapsedTicks(LReadLnStartTime) >= UInt32(ATimeout) then begin
FReadLnTimedOut := True;
end;
end;
if FReadLnTimedOut then begin
Result := '';
Exit;
end;
EDIT: Using the New TIdHTTP hoNoReadMultipartMIME flag sample, i wrote a test app to try get the image from the boundary
var
Boundary, Line: string;
TCPStream: TIdTCPStream;
NewDecoder, Decoder: TIdMessageDecoder;
MsgEnd: Boolean;
BodyStream: TStream;
Jpg: TJpegImage;
begin
{
The code below comes from Indy Project Blog by Remy Lebeau
This connection requires Digest Auth, so i set BasicAuth to False, put the flag hoInProcessAuth
And implement the OnAuthorization and OnSelectAuthorization, the select is needed to do something to the Authorization works,
do not know why.
}
HTTP.HTTPOptions := [hoInProcessAuth, hoForceEncodeParams, hoNoReadMultipartMIME];
HTTP.Get('http://192.168.1.205/cgi-bin/snapManager.cgi?action=attachFileProc&Flags[0]=Event&Events=[AccessControl]');
//Here the response always return HTTP.Response.KeepAlive FALSE, so i exclude it from test
if IsHeaderMediaType(HTTP.Response.ContentType, 'multipart') then //and HTTP.Response.KeepAlive
begin
Boundary := ExtractHeaderSubItem(HTTP.Response.ContentType, 'boundary', QuoteHTTP);
repeat
Line := HTTP.IOHandler.ReadLn;
until (Line = ('--' + Boundary)) or (Line = ('--' + Boundary + '--'));
TCPStream := TIdTCPStream.Create(HTTP);
try
Decoder := TIdMessageDecoderMIME.Create(nil);
try
TIdMessageDecoderMIME(Decoder).MIMEBoundary := Boundary;
MsgEnd := False;
repeat
TIdMessageDecoderMIME(Decoder).SourceStream := TCPStream;
TIdMessageDecoderMIME(Decoder).FreeSourceStream := False;
Decoder.ReadHeader;
case Decoder.PartType of
mcptText: begin
BodyStream := TMemoryStream.Create;
try
NewDecoder := TIdMessageDecoderMIME(Decoder).ReadBody(BodyStream, MsgEnd);
try
BodyStream.Position := 0;
mLog.Lines.LoadFromStream(BodyStream); //<-- OK i got the text data from body and showing in a memo
finally
Decoder.Free;
Decoder := NewDecoder;
end;
finally
BodyStream.Free;
end;
end;
mcptAttachment: begin
BodyStream := TMemoryStream.Create;
try
BodyStream.Position := 0;
NewDecoder := TIdMessageDecoderMIME(Decoder).ReadBody(BodyStream, MsgEnd); //<-- here comes a close gracefully,
//so i debug the ReadBody and found a exception on line 438 of idMessadeCoderMime
// LLine := ReadLnRFC(VMsgEnd, LF, '.', LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF}); {do not localize}
//When it try to read a exception occurs and the connection closes gracefully
//but it read a lot of data befora except, so i thinking is something about a end of msg missing or misformed
jpg := TJPEGImage.Create;
try
BodyStream.Position := 0;
jpg.LoadFromStream(BodyStream);
jpg.SaveToFile('C:\Producao\API_SDK\Facial\teste.jpg');
finally
jpg.Free;
Decoder.Free;
Decoder := NewDecoder;
end;
finally
BodyStream.Free;
end;
end;
mcptIgnore: begin
FreeAndNil(Decoder);
Decoder := TIdMessageDecoderMIME.Create(nil);
TIdMessageDecoderMIME(Decoder).MIMEBoundary := Boundary;
end;
mcptEOF: begin
FreeAndNil(Decoder);
MsgEnd := True;
end;
end;
until (Decoder = nil) or MsgEnd;
finally
Decoder.Free;
end;
finally
TCPStream.Free;
end;
end;
end;
The part of the code mcptAttachment when NewDecoder := Decoder.ReadBody(BodyStream, MsgEnd); is called, the readbody funtion run, reading the bytes until it crashes before reach the 'Content-Length' size.
I´m trying to isolate when it crashes, but one thing is for sure, the error occurs when it try to read the next data. but i can´t find the trigger for the exception on indy source yet
EDIT: Got a imagem but can´t keep reading until server close connection cause the response alredy comes closed.
Workin Code
var
Boundary, Line: string;
TCPStream: TIdTCPStream;
NewDecoder, Decoder: TIdMessageDecoder;
MsgEnd: Boolean;
BodyStream: TStream;
Jpg: TJpegImage;
begin
HTTP.HTTPOptions := [hoInProcessAuth, hoForceEncodeParams, hoNoReadMultipartMIME];
HTTP.Get('http://192.168.1.205/cgi-bin/snapManager.cgi?action=attachFileProc&Flags[0]=Event&Events=[AccessControl]');
if IsHeaderMediaType(HTTP.Response.ContentType, 'multipart') then
begin
Boundary := ExtractHeaderSubItem(HTTP.Response.ContentType, 'boundary', QuoteHTTP);
repeat
Line := HTTP.IOHandler.ReadLn;
until (Line = ('--' + Boundary)) or (Line = ('--' + Boundary + '--'));
TCPStream := TIdTCPStream.Create(HTTP);
try
Decoder := TIdMessageDecoderMIME.Create(nil);
try
TIdMessageDecoderMIME(Decoder).MIMEBoundary := Boundary;
MsgEnd := False;
repeat
TIdMessageDecoderMIME(Decoder).SourceStream := TCPStream;
TIdMessageDecoderMIME(Decoder).FreeSourceStream := False;
if not http.IOHandler.InputBufferIsEmpty then
begin
Decoder.ReadHeader;
case Decoder.PartType of
mcptText: begin
BodyStream := TMemoryStream.Create;
try
NewDecoder := TIdMessageDecoderMIME(Decoder).ReadBody(BodyStream, MsgEnd);
try
BodyStream.Position := 0;
mEvent.Lines.LoadFromStream(BodyStream);
finally
Decoder.Free;
Decoder := NewDecoder;
end;
finally
BodyStream.Free;
end;
end;
mcptAttachment: begin
BodyStream := TMemoryStream.Create;
http.IOHandler.InputBuffer.ExtractToStream(BodyStream);
try
BodyStream.Position := 0;
jpg := TJPEGImage.Create;
try
jpg.LoadFromStream(BodyStream);
JvImage1.Picture.Assign(jpg);
jpg.SaveToFile('C:\Producao\API-SDK\Facial\teste.jpg');
finally
jpg.Free;
FreeAndNil(Decoder);
Decoder := TIdMessageDecoderMIME.Create(nil);
TIdMessageDecoderMIME(Decoder).MIMEBoundary := Boundary;
end;
finally
BodyStream.Free;
end;
end;
mcptIgnore: begin
mLog.Lines.Add('Ignore');
FreeAndNil(Decoder);
Decoder := TIdMessageDecoderMIME.Create(nil);
TIdMessageDecoderMIME(Decoder).MIMEBoundary := Boundary;
end;
mcptEOF: begin
mLog.Lines.Add('Fim');
FreeAndNil(Decoder);
MsgEnd := True;
end;
end;
end
else
begin
http.IOHandler.CheckForDisconnect(False,True);
msgend := True
end;
until (Decoder = nil) or MsgEnd;
finally
Decoder.Free;
end;
finally
TCPStream.Free;
end;
end;
end;
What you are asking for can be done with TIdHTTP, but it takes some extra work. Details are in the following blog article on Indy's website:
https://www.indyproject.org/2014/03/05/new-tidhttp-honoreadmultipartmime-flag/
In a nutshell, you need to enable the hoNoReadMultipartMIME flag in the TIdHTTP.HTTPOptions property, so that TIdHTTP.Get() won't try to read the MIME data from the TIdHTTP.IOHandler after receiving the HTTP headers. That will allow you to read the MIME data yourself. You can use Indy's TIdMessageDecoderMIME class to help with that reading. There is a code example provided in the blog article.
I have some script in some file "MyScript.sql"
On the form I have my TProgressBar.
I want to read script with TFDScript and move progressbar according to the script.
My code is
Var
Lista: TStringList; // SQL DDL list for creating table and populate table
I: Integer;
Begin
With FDConn Do //FDConn is my FaireDac connection
Begin
LoginPrompt := False;
With Params Do
Begin
Clear;
DriverID := 'SQLite';
Database := 'MyDatabase.sdb';
LoginPrompt := False;
End;
Lista := TStringList.Create;
Lista.Clear;
Try
FDScript.ValidateAll; //FDScript is TFDScript and prgBar is TProgressBar
prgBar.Max := FDScript.TotalJobSize - 1;
prgBar.Update;
Lista.Clear;
Lista.LoadFromFile('MyScript.sql');
// Now how I can read script 1 line by 1 line and move progress bar with
prgBar.StepIt;
prgBar.Update;`
You can handle the OnProgress event and read there e.g. TotalJobSize property to determine the number of bytes to proceed and TotalJobDone to get number of bytes processed. For example:
procedure TForm1.FDScript1Progress(Sender: TObject);
begin
ProgressBar1.Max := TFDScript(Sender).TotalJobSize;
ProgressBar1.Position := TFDScript(Sender).TotalJobDone;
end;
If you were having progress bar control with progress value setup by percentage, you'd better read the TotalPct10Done property.
I am trying to create video streaming server using Indy Http server. I am using ranged requests to send large files. One chunk of data is 10 Mb long. If video file which requests client is smaller than 10 Mb then it is all ok and vido is played. But if file size is longer than 10 Mb I return first chunk of data. Then client asks me for another chunk of data from the end of file and then my client says that it is unrecognizable video format. Can someone tell me where is problem in my code.
my server code
procedure TForm1.Button1Click(Sender: TObject);
begin
Caption := 'Running';
FServer := TIdHTTPServer.Create(Self);
FServer.DefaultPort := 7070;
FServer.OnCommandGet:=#External_Get;
FServer.Active := True;
end;
procedure TForm1.External_Get(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
FS: TFileStream;
Ranges: TIdEntityRanges;
Range: TIdEntityRange;
begin
Ranges := ARequestInfo.Ranges;
Range := Ranges.Ranges[0];
FS := TFileStream.Create('/home/user/Desktop/large_file.mp4', fmOpenRead or fmShareDenyWrite);
AResponseInfo.ContentType := 'video/mp4';
AResponseInfo.AcceptRanges := 'bytes';
AResponseInfo.ContentStream := TIdHTTPRangeStream.Create(
FS,
Range.StartPos,
Range.StartPos + 1024*1024*10,
True
);
AResponseInfo.FreeContentStream := True;
AResponseInfo.ContentRangeStart := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeStart;
AResponseInfo.ContentRangeEnd := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeEnd;
AResponseInfo.ContentRangeInstanceLength := AResponseInfo.ContentRangeEnd - Range.StartPos + 1;
AResponseInfo.ContentLength := FS.Size;
AResponseInfo.ResponseNo := 206;
end;
And here is my client code (I use firefox):
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
</head>
<body>
<video width="400" controls>
<source src="http://localhost:7070/test38.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
</body>
</html>
There are several errors in your server code.
You are not validating that a range is actually being requested, or even respecting an end range if one is present.
You are setting the AResponseInfo.ContentLength property to the full size of the file, even when you are not sending the full file at one time. That value belongs in the AResponseInfo.ContentRangeInstanceLength property instead when sending a ranged response. You must set ContentLength to the size of the data actually being sent in the response, which in this case is your current range chunk. It is best not to set the ContentLength at all, you can let the server calculate it for you based on the assigned ContentStream.
You are setting the AResponseInfo.ResponseNo property to 206 unconditionally, even if a range is not requested at all, or if the requested range cannot be satisfied. TIdHTTPRangeStream performs validations in its constructor and sets its ResponseCode property accordingly. That is the value you should be assigning to ResponseNo.
Try something more like this instead:
procedure TForm1.External_Get(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
FS: TFileStream;
Range: TIdEntityRange;
StartPos, EndPos: Int64;
begin
if not FileExists('/home/user/Desktop/large_file.mp4') then
begin
AResponseInfo.ResponseNo := 404;
Exit;
end;
try
FS := TFileStream.Create('/home/user/Desktop/large_file.mp4', fmOpenRead or fmShareDenyWrite);
except
AResponseInfo.ResponseNo := 500;
Exit;
end;
AResponseInfo.ContentType := 'video/mp4';
AResponseInfo.AcceptRanges := 'bytes';
if ARequestInfo.Ranges.Count = 1 then
begin
Range := ARequestInfo.Ranges.Ranges[0];
StartPos := Range.StartPos;
EndPos := Range.EndPos;
if StartPos >= 0 then
begin
// requesting prefix range from BOF
if EndPos >= 0 then
EndPos := IndyMin(EndPos, StartPos + (1024*1024*10) - 1)
else
EndPos := StartPos + (1024*1024*10) - 1;
end else
begin
// requesting suffix range from EOF
if EndPos >= 0 then
EndPos := IndyMin(EndPos, 1024*1024*10)
else
EndPos := (1024*1024*10);
end;
AResponseInfo.ContentStream := TIdHTTPRangeStream.Create(FS, StartPos, EndPos);
AResponseInfo.ResponseNo := TIdHTTPRangeStream(AResponseInfo.ContentStream).ResponseCode;
if AResponseInfo.ResponseNo = 206 then
begin
AResponseInfo.ContentRangeStart := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeStart;
AResponseInfo.ContentRangeEnd := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeEnd;
AResponseInfo.ContentRangeInstanceLength := FS.Size;
end;
end else
begin
AResponseInfo.ContentStream := FS;
AResponseInfo.ResponseNo := 200;
end;
end;
I have the following Go code
ciphertext := "Zff9c+F3gZu/lsARvPhpMau50KUkMAie4j8MYfb12HMWhkLqZreTk8RPbtRB7RDG3QFw7Y0FXJsCq/EBEAz//XoeSZmqZXoyq2Cx8ZV+/Rw="
decodedText, _ := base64.StdEncoding.DecodeString(ciphertext)
decodedIv, _ := base64.StdEncoding.DecodeString("u9CV7oR2w+IIk8R0hppxaw==")
newCipher, _ := aes.NewCipher([]byte("~NB8CcOL#J!H?|Yr"))
cfbdec := cipher.NewCBCDecrypter(newCipher, decodedIv)
cfbdec.CryptBlocks(decodedText, decodedText)
data, _ := base64.StdEncoding.DecodeString(string(decodedText))
println(string(data))
The output is {"data":{"value":300}, "SEQN":700 , "msg":"IT WORKS!!"
It's encrypted with the following CryptoJS
function encrypt(message, key) {
let keyHex = CryptoJS.enc.Hex.parse(parseToHex(key))
let iv = CryptoJS.lib.WordArray.random(128 / 8);
let wordArray = CryptoJS.enc.Utf8.parse(message);
let base64 = CryptoJS.enc.Base64.stringify(wordArray);
let encrypted = CryptoJS.AES.encrypt(base64, keyHex, { iv: iv });
return {
cipher: encrypted.ciphertext.toString(CryptoJS.enc.Base64),
iv: CryptoJS.enc.Base64.stringify(iv),
length: base64.length,
size: encrypted.ciphertext.sigBytes,
}
}
And can be decrypted with
function decrypt(message, key, iv) {
let ivEX = CryptoJS.enc.Hex.parse(decodeToHex(iv));
let keyEX = CryptoJS.enc.Hex.parse(parseToHex(key));
let bytes = CryptoJS.AES.decrypt(message, keyEX , { iv: ivEX});
let plaintext = bytes.toString(CryptoJS.enc.Base64);
return decodeToString(decodeToString(plaintext));
}
The output is {"data":{"value":300}, "SEQN":700 , "msg":"IT WORKS!!" } - this is the correct output
Why Go has different output?
Check your errors please. ALWAYS
illegal base64 data at input byte 75
https://play.golang.org/p/dRLIT51u4I
More specifically, the value at byte 75 is 5, which is out of the range of characters available to base64. In ascii, it is the ENQ (enquiry) character. As to why this ends up in your final base64 string is beyond me.
EDIT: OK found the issue. For whatever reason, the base64 padding character = at the end is being decrypted as 5 consecutive bytes containing the value 5. Here is a playground link that shows it fixed. https://play.golang.org/p/tf3OZ9XG1M
EDIT: As per matt's comments. I updated the fix function to simply remove all the PKCS7 block padding and use RawStdEncoding for the last base64 decode. This should now be a reasonable fix.