Recent

Author Topic: Anyone interested in using GPGME.dll (GNU PG) could use some help, it's working  (Read 13679 times)

snorkel

  • Hero Member
  • *****
  • Posts: 817
Hi,
I had a need to be able to use GPG in a app and I did get it working with tprocess and gpg.exe, however it's a bit clunky so I found this:

http://www.gnu-pascal.de/contrib/nicola/gpgme.pas

I actually got it to compile but I could use some help with one part I couldn't get working:

type
  PProc = ^procedure;

procedure GpgmeRegisterIdle (Proc: PProc); asmname 'gpgme_register_idle';

I just commented it out.

Also to use the ported unit you need:

gpgme.dll (I renamed the one in gpg4win to this)
libassuan-0.dll
libgpg-error-0.dll

you can get them in theGpg4win download from https://www.gpg4win.org/download.html


Also if someone with more porting experience wanted to look at the gpgme.pas to make sure I did things the correct way.
(some iffy things where VoidGpgmeCtx        = restricted Void;)  I just used a type to map void to a string, no idea if that is right way.

It does work and so far the only function I tried was:

procedure TForm1.Button1Click(Sender: TObject);
var
  Version:pchar;
begin
     Version := GpgmeCheckVersion (nil);
     showmessage(string(version));
end;


If we can get this working I would be happy to do a WIKI page on it.

Also not sure about licensing, but I would imagine we could just keep the header intact and use the GPL as stated in said header.

The other thing is this is very old and and is probably missing features.










 



« Last Edit: March 17, 2016, 05:27:31 pm by snorkel »
***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
I actually got it to compile but I could use some help with one part I couldn't get working:

type
  PProc = ^procedure;
GNU Pascal "intelligently" reinvent procedural type as function pointer as implemented by its mother GCC, so you can simply remove that caret.
(some iffy things where VoidGpgmeCtx        = restricted Void;)  I just used a type to map void to a string, no idea if that is right way.
That's GNU Pascal way of saying opaque type. Usually it's implemented as empty record in TP/Delphi/FPC. Pointer to that record is used to represent the value that shouldn't be directly modified, only to be passed as parameters or returned from function.

snorkel

  • Hero Member
  • *****
  • Posts: 817
I attached a updated version.
It compiles fine and some of the functions work.
far as I can get is:

       error:= GpgmeNew(ctx);
       ShowMessage(string(GpgmeStrError(error)));
       error:= GpgmeDataNewFromFile(indata,'C:\Users\sn\Desktop\dllexp.chm',false);
       ShowMessage(string(GpgmeStrError(error)));
       error:= GpgmeDataNewFromFile(outdata,'C:\Users\sn\Desktop\dllexp.pgp',false);
       ShowMessage(string(GpgmeStrError(error)));   


There are a bunch of functions defined that have no entry point anymore and a lot of the function params have changed since this unit was created.
for example the gpgme_op_encrypt now has 4 params instead of 3.

i.e.

Function: gpgme_error_t gpgme_op_encrypt (gpgme_ctx_t ctx, gpgme_key_t recp[], gpgme_encrypt_flags_t flags, gpgme_data_t plain, gpgme_data_t cipher)

https://www.gnupg.org/documentation/manuals/gpgme/Encrypting-a-Plaintext.html

I tried running the actual C header gpgme.h through the H2PAS converter included with Lazarus but that had many many errors and could not convert it.

I am going to have to give up on this for now, it's taking too much time :-(   I just don't have the C knowledge to figure everything out.

For now I am just going to use tprocess with gpg.exe.



***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

snorkel

  • Hero Member
  • *****
  • Posts: 817
Well, I had a break through kind of, I found a partially implemented example here that uses loadlibrary:
https://github.com/marsupilami79/gpgme4pascal

It was missing decryption,so I added that and I also added the passphrase call back, which actually sort of works.
When gpgme needs a passphrase it calls this callback, and the params are populated as according to gpgme docs.
The problem is it hangs after it returns.  I don't know if I am writing to the C file descriptor (param fd) correctly and that's why it's hanging?
The filewrite does not error and returns the bytes written.

It could also be a issue with the win32 gpgme.dll version I am using, it's fairly hard to find a prebuilt binary of versions that don't implement the pinentry dialog box.

Code: Pascal  [Select][+][-]
  1. function gpgme_passphrase_cb(handle:pointer;uid_hint:pchar;passphrase_info:pchar;prev_was_bad:integer;fd:integer):Tgpgme_error;cdecl;
  2. var
  3.   aerror:Tgpgme_error;
  4.   password:string;
  5.   byteswritten:integer;
  6.   filehandle:thandle;
  7. begin
  8.      filehandle:=thandle(fd);
  9.      password:='4656565'+#10;
  10.      byteswritten:=FileWrite(filehandle,password,Length(password));
  11.  
  12.      result.errorcode:=GPG_ERR_NO_ERROR;
  13.      result.error:=0;
  14.      result.errorsource:=0;
  15. end;

Anyone have ideas?



***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

molly

  • Hero Member
  • *****
  • Posts: 2330
You are trying to use FPC file functions on a c file handle (descriptor) ? Did i read that correctly ?

I don't think you are suppose to do that. Instead use the filefunctions of the c library that the dll was linked against (most probably mscvrt, but honestly that would be a guess. Check the dependencies of the pgp dll for that to make sure).

edit:
Please forgive my ignorance, but i had a closer look. The only function by that name as you showed is a call-back function, but then the parameters don't seem to match.

There is a 'set' variant of that function you showed (gpgme_set_passphrase_cb) but that also seems to use other parameters not compliant with the shown function declaration.

I got my info from here, in combination with your given links. feel free to correct me in case necessary.
« Last Edit: March 18, 2016, 05:54:32 pm by molly »

snorkel

  • Hero Member
  • *****
  • Posts: 817
Hi Molly,
Yes, in the gpgme.dll there are two functions,
one is to set the call back and the other to call it.

The callback is working, when the gpgme.dll calls it, it has the parms populated as per the docs and I can see the values in the debugger.
I attached a pic of the watch list populated with the parms and the correct values.

I have been looking around at other bindings like for python etc and they all just write to the descriptor with similar functions.

***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

snorkel

  • Hero Member
  • *****
  • Posts: 817
I found that if I close the descriptor :

FileClose(filehandle);

It does not hang and raises a bad passphrase error.  So it has to be something it does not like with the way I am writting the file.
maybe I need to allocate memory for it using the fd as the pointer?  I don't know, but I will continue to hack away at it.
***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

molly

  • Hero Member
  • *****
  • Posts: 2330
I'm not telling you that you are doing it wrong, just that things looks odd for me.

Usually, speaking of normal c functionaility, your code should lokos something like this:
Code: Pascal  [Select][+][-]
  1. Type
  2.   TGpgmePassphraseCb = function(hook: Pointer; desc: PChar; r_hd: PPointer): PChar;
  3.  
  4. Procedure gpgme_set_passphrase_cb (ctx: TGpgmeCtx; cb:TGpgmePassphraseCbFunction; hook_value: Pointer); cdecl;
  5.  
  6. Procedure gpgme_get_passphrase_cb (ctx: TGpgmeCtx; cb: TGpgmePassphraseCbFunction; hook_value: PPointer); cdecl;
  7.  
  8. Function a_CallBackFunction(hook: Pointer; desc: PChar; r_hd: PPointer): PChar;
  9. begin
  10.   // do something here
  11. end;
  12.  
  13. Var
  14.   a_ctx: TGpgmeCtx;
  15.   a_HookValue : Pointer;
  16.  
  17. begin
  18.   gpgme_set_passphrase_cb(a_ctx, @a_CallBackFunction; a_HookValue);
  19.   gpgme_get_passphrase_cb(a_ctx, @a_CallBackFunction; @a_PHookValue);
  20. end.
  21.  

If truly a c descriptor, then you are not allowed to use pascal file related functions on them. Pascal filehandle <> c file descriptor. Most other implementation are allowed to do so as they use the same c library using the same functions from the same c library to operate on files.

seeing that 404, as representing a filehandle tells me enough ;-)

snorkel

  • Hero Member
  • *****
  • Posts: 817
It's like this:
Code: Pascal  [Select][+][-]
  1. Tgpgme_passphrase_cb_t  = function(handle:pointer;uid_hint:pchar;passphrase_info:pchar;prev_was_bad:integer;fd:integer):Tgpgme_error;cdecl;
  2.  
  3. aproc = Tgpgme_passphrase_cb_t;
  4.  
  5.  
  6. gpgme_set_passphrase_cb(context,aproc,nil);


the set passphrase is declared like this:
Code: Pascal  [Select][+][-]
  1. Tgpgme_set_passphrase_cb = procedure(ctx: Pgpgme_ctx_t;passfunc:Tgpgme_passphrase_cb_t;hook_value:pointer);cdecl;

Code: Pascal  [Select][+][-]
  1. var
  2.  
  3. gpgme_set_passphrase_cb:Tgpgme_set_passphrase_cb;  


Then in the loaddll function:

Code: Pascal  [Select][+][-]
  1. gpgme_set_passphrase_cb:= InitFunction('gpgme_set_passphrase_cb');


I really don't know what the fd file descriptor var actually is, maybe it's STDOUT?

I agree with you I don't think the filewrite is actually writing to that fd var.

If I step through the call back slowly it does not hang and returns after I do a fileclose(filehandle) and it returns a bad passphrase error.

having the fileclose does prevent it from hanging.


There must be a way to write to a C file descriptor from FPC.  The newer versions of gpgme do have a function in the DLL called gpgme_io_writen which the docs say to use, the only issue is the newer versions don't use the callback anymore and instead have a pinentry agent that pops up a dialog for the pass phrase, which of course is bad for a server .

I may look around at the older gpgme source and see if that gpgme_io_writen is avaialbe in any older versions.





***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

molly

  • Hero Member
  • *****
  • Posts: 2330
I'm a bit confused about the parameters declared inside the callback function. I'm unable to locate your used definition of the callback function anywhere.

Would you please be so kind (if possible) as to link to the source-code that you are using to implement this for Pascal ? As neither links you pointed to show a callback function with the parameters you're currently use for your callback declaration (not saying that you are wrong there).

Otherwise i'll keep running around in circles, because i'm using the 'wrong' reference material.

BTW: the second link you linked to (https://github.com/marsupilami79/gpgme4pasca), showed that it is using a stream adapter to process (read/write) the data. But as said by original author, it is missing quite a few functions and is far from finished (and according to author might even contain bugs).


There must be a way to write to a C file descriptor from FPC.
Yes, there is: By calling the corresponding c library file functions that can operate on such descriptor.

It is not that hard to do as it requires only those functions from the c dll that was linked against and that you really need (e.g. no need to create a complete interface unit).

Of course, that only applies when we are talking about a true c descriptor (i am unable to verify as none of the links i am currently looking at, uses a file descriptor anywhere in its exported library functions).
« Last Edit: March 18, 2016, 07:38:34 pm by molly »

snorkel

  • Hero Member
  • *****
  • Posts: 817
This is interesting:

http://lists.gnupg.org/pipermail/gnupg-users/2011-February/040645.html

The def from the gpgme docs:

https://www.gnupg.org/documentation/manuals/gpgme/Passphrase-Callback.html

The stream adapter in (https://github.com/marsupilami79/gpgme4pasca) is used to read/write the cipher/plain text.   It has a few callbacks of it's own for that.
If you really want to see my hacking :-)  I can zip it up and post a google drive link.

it's just the same as the git hub example stuff with the addition of decrypt and the passphrase call back.
If I use it with newer gpgme it's popups up a GTK dialog if in needs a password, which is kind of weird as you can't use it on a server then.


« Last Edit: March 18, 2016, 07:52:55 pm by snorkel »
***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

molly

  • Hero Member
  • *****
  • Posts: 2330
First of all, no need to zip anything up right now :-)

I was simply lost in all different version floating around. Thank you for the link.

Ok, so that looks ok. Are you sure your dll is also version 1.6.0 (as that is what the documentation refers to) ?

Secondly i came across this part, which might or might not work for you.

Furthermore, there are io initialization functions being described here, but when looking at the actual implementation here i have to be honest and say that such code is really a bit too much for me to be able to cope with : that is one ugly piece of code :-)
 :-[

snorkel

  • Hero Member
  • *****
  • Posts: 817
yes, and the docs really suck :-)

I tried this also:

function __write(fd:integer;buffer:pchar;count:integer):integer; external msvcrtdll name '_write';
procedure __close(fd:integer); external msvcrtdll name '_close'; 

Compiles, but when I use the __write function it returns a huge number not the 9 bytes I wrote.
I don't knowif the params are correct for these.
I then did:

password:='12345678'+#10;
ret:=__write(fd,password,length(buffer));



***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

molly

  • Hero Member
  • *****
  • Posts: 2330
Well, i would suspect that the passphrase is stored encrypted ?

i am not entirely sure yest how the api works, but are you perhaps able to read the passphrase back, e.g. returning the phrase you entered (when you wrote it) ?

snorkel

  • Hero Member
  • *****
  • Posts: 817
It's stored encrypted but passed to the api plain text.

***Snorkel***
If I forget, I always use the latest stable 32bit version of Lazarus and FPC. At the time of this signature that is Laz 3.0RC2 and FPC 3.2.2
OS: Windows 10 64 bit

 

TinyPortal © 2005-2018