What about providing a custom N-Factor authentication mechanism?
Before combining available methods, let's assume we can perform the following:
1) Hard-code inside the Java program
2) Store in a .properties file
3) Ask user to type password from command line
4) Ask user to type password from a form
5) Ask user to load a password-file from command line or a form
6) Provide the password through network
7) many alternatives (eg Draw A Secret, Fingerprint, IP-specific, bla bla bla)
1st option: We could make things more complicated for an attacker by using obfuscation, but this is not considered a good countermeasure. A good coder can easily understand how it works if he/she can access the file. We could even export a per-user binary (or just the obfuscation part or key-part), so an attacker must have access to this user-specific file, not another distro.
Again, we should find a way to change passwords, eg by recompiling or using reflection to on-the-fly change class behavior.
2nd option: We can store the password in the .properties file in an encrypted format, so it's not directly visible from an attacker (just like jasypt does). If we need a password manager we'll need a master password too which again should be stored somewhere - inside a .class file, the keystore, kernel, another file or even in memory - all have their pros and cons.
But, now users will just edit the .properties file for password change.
3rd option: type the password when running from command line e.g. java -jar /myprogram.jar -p sdflhjkiweHIUHIU8976hyd
.
This doesn't require the password to be stored and will stay in memory. However, history
commands and OS logs, may be your worst enemy here.
To change passwords on-the-fly, you will need to implement some methods (eg listen for console inputs, RMI, sockets, REST bla bla bla), but the password will always stay in memory.
One can even temporarily decrypt it only when required -> then delete the decrypted, but always keep the encrypted password in memory. Unfortunately, the aforementioned method does not increase security against unauthorized in-memory access, because the person who achieves that, will probably have access to the algorithm, salt and any other secrets being used.
4th option: provide the password from a custom form, rather than the command line. This will circumvent the problem of logging exposure.
5th option: provide a file as a password stored previously on a another medium -> then hard delete file. This will again circumvent the problem of logging exposure, plus no typing is required that could be shoulder-surfing stolen. When a change is required, provide another file, then delete again.
6th option: again to avoid shoulder-surfing, one can implement an RMI method call, to provide the password (through an encrypted channel) from another device, eg via a mobile phone. However, you now need to protect your network channel and access to the other device.
I would choose a combination of the above methods to achieve maximum security so one would have to access the .class files, the property file, logs, network channel, shoulder surfing, man in the middle, other files bla bla bla. This can be easily implemented using a XOR operation between all sub_passwords to produce the actual password.
We can't be protected from unauthorized in-memory access though, this can only be achieved by using some access-restricted hardware (eg smartcards, HSMs, SGX), where everything is computed into them, without anyone, even the legitimate owner being able to access decryption keys or algorithms. Again, one can steal this hardware too, there are reported side-channel attacks that may help attackers in key extraction and in some cases you need to trust another party (eg with SGX you trust Intel). Of course, situation may worsen when secure-enclave cloning (de-assembling) will be possible, but I guess this will take some years to be practical.
Also, one may consider a key sharing solution where the full key is split between different servers. However, upon reconstruction, the full key can be stolen. The only way to mitigate the aforementioned issue is by secure multiparty computation.
We should always keep in mind that whatever the input method, we need to ensure we are not vulnerable from network sniffing (MITM attacks) and/or key-loggers.