The approach is ok and is as secure as is pipeing the password in the shell <<<"myPassword" veracrypt
.
- There is no password in the
ps
output.
- The password is stored in temporary buffers only.
- I think an attacker could still get the password using some side channel attacks, if it knows enough about your application/source code.
Your code is not secure at all.
- You don't check the return value of malloc
- You don't check the return value of popen
- You don't check the return value of getpass
- You overflow the allocated memory for
cc
. You didn't allocate place for the terminating null character. You could use asnprintf
and let GNU library do the job for you.
- Because you don't pass properly the
argv[i]
and argv[i+1]
it's plain simple to attack any PC using your program, with just ex.: ./your_program "; sudo rm -rf <some_file>" "; echo I can run any shell script here"
.
Is this approach a good idea at all? (securitywise)
The approach is ok, how you approached it is not ok. Your program leaks memory and doesn't check any return values and has no control over the strings passed to popen
, which is just unsecure. Using system(sudo echo -n)
is also insecure. As for the approuch, would be best to bzero the buffer after it's last use memset(buffer, 0, strlen(buffer) + 1)
(maybe multiple times, like 5), and then free(buffer)
.
In the light of last attacks like Meltdown and Spectre and others, newer ssh versions encrypt the password with a long key (I think with RSA, not sure) right after receiving it from user and decrypt each time upon use. The key is long enough to make attacks using such methods not probable or too long. I don't think there is need for easy small application to implement such method. source.
How is the value of buffer piped to veracrypt by popen()?
Because you use fprintf
, the buffer is copied into the internal FILE*
buffer and then flushed on the newline. By default FILE*
streams are buffered and flushed on newline. You can specify the behavior with setvbuf
, however, I don't think it's safe at all, as the password will remain in the FILE*
buffer for some time. Then the fprintf
call writes the content of the internal FILE*
buffer upon newline to the associated pipe file descriptor with the FILE*
pointer. Then kernel passes the data from the pipe's input to the command's stdin. A little tiny bit safer way (as you don't need printf
utility at all, you just "%s"
...), is probably to use setvbuf(fChild, NULL, _IONBF, 0)
and then to use fwrite(buffer, strlen(buffer), 1, fChild)
.
A proper approach would be to remove the FILE*
and to use the proper pipe()
+ fork()
+ exec()
and stream the password directly into the pipe with write()
call, so you don't use FILE*
internal buffering. fork()
will also allow you to send signals and handle the return value of the child.
Is buffer read directly from its location or is it copied and can therefore remain somewhere in memory?
Yes and yes and yes. It is read directly from it's location inside fprintf
call. It is copied into internal FILE*
buffer. It can therefore remain somewhere in memory.