2

I'm developing a kind-of secure password manager. It won't be for professional use, and I know it won't be as secure as KeePass or anything. This is just for my own understanding of how to allocate secure memory, using crypto-algorithms etc.

For this I work with libgcrypt and allocate my memory with gcry_malloc_secure.

I've now come to a point where I somehow need the user to enter his password for encryption/decryption. But as I see it, any console input is first buffered in stdin (or argv[..]) and thus not in secure memory. So it could "easily" be read by an attacker.

Any security-related thing that happens inside my program is in securemem and hopefully harder to read/steal.

So my question is like the title states:

What is the most secure way to let a user input data?

KillPinguin
  • 390
  • 4
  • 15
  • There's **no** way in C, so solutions will depend on the platform. Maybe having a look at the [pinentry source](https://github.com/GPGTools/pinentry) could give some ideas. –  Aug 25 '17 at 06:23
  • Maybe this could help: [Buffered and Unbuffered inputs in C](https://stackoverflow.com/questions/20342772/buffered-and-unbuffered-inputs-in-c). – Andre Kampling Aug 25 '17 at 06:24
  • @FelixPalmen could you explain why there is no way? (Except for keyloggers..) And if I limited myself on POSIX, would there be a solution? – KillPinguin Aug 25 '17 at 07:04
  • 1
    @KillPinguin simply because C as a language only provides `stdio` and while you can disable the buffering of `stdio` streams, there are no means to control what the OS is doing. Of course there **are** platform-specific ways. I'm not sure POSIX specifies anything useful for that, I'm not in that topic. Just thought that `pinentry` probably "*does it right*", so looking at the source *might* help. –  Aug 25 '17 at 07:12
  • [I see what you did, there](https://en.wikipedia.org/wiki/History_of_Linux#The_creation_of_Linux). – unwind Aug 25 '17 at 08:48
  • @unwind sorry, I don't get the joke :/ – KillPinguin Aug 25 '17 at 16:47
  • "What is the most secure way to let a user input data?" --> Also do remember to cleanup afterwards. Scrub your buffers and variables at the end of each function. – chux - Reinstate Monica Aug 25 '17 at 16:58

1 Answers1

0

If by "secure" memory you mean memory that won't be paged to disk, a POSIX-compliant C environment should provide mlock() at least. So you can create a buffer that won't be paged. But you still have to find a way to read data into it, and you might have to zero it before freeing it, to avoid having the sensitive data lurking about in the process space.

I suppose a rudimentary way to implement what you need would be to create a buffer, apply mlock() to it, and then read input character-by-character into that buffer.

If you use stdio.h calls, however, you're still going to fall foul of the buffering that goes on automatically. On Linux you can turn this buffering off at the terminal level, and then read characters one-by-one using ioctl() calls. Libraries like ncurses have their own ways of doing similar things. I presume similar effects can be achieved on other platforms, but I don't know enough about them to comment.

Kevin Boone
  • 4,092
  • 1
  • 11
  • 15
  • Honestly I'm not sure what secure memory really is. It's just an option of ligcrypt... should really look that one up. I like the idea of reading the input character by character. If I would add enough noise to the stdin-Buffer, that could maybe work. – KillPinguin Aug 25 '17 at 16:49
  • Usually by "secure memory" is meant memory that won't be paged. However, there are ways to implement cryptographically secure memory, by keeping the contents encrypted. I think that libgcrypt uses the term in the former sense. Is this Linux? – Kevin Boone Aug 27 '17 at 06:52
  • On Linux you can (in principle) turn off buffering by using tcsetattr() to remove the ICANON attribute on STDIN_FILENAME. Then you can read character-by-character using the FIONREAD ioctl() call. If it's password stuff, you probably need to remove the ECHO attribute as well. All this stuff is pretty well-document, but I can dig out some source if you can't find any. The only slightly non-standard part will be using mlock() to prevent your data buffers being paged to swap. I have to point out, however, that it's difficult to be absolutely certain that nothing is buffered in the kernel. – Kevin Boone Aug 27 '17 at 12:39