sshtools / maverick-synergy

Next Generation Java SSH API
https://jadaptive.com
GNU Lesser General Public License v3.0
96 stars 26 forks source link

Unable to decrypt SSH privatekey #86

Open jarvijuk opened 6 months ago

jarvijuk commented 6 months ago

Hello,

We have been testing SSH connection with encrypted private keys and it works when using the default encryption (aes256-ctr). However if alternative cipher is used, privatekey decryption fails

Used versions

Maverick-synergy: 3.1.1 Maverick-bc: 3.1.1

java.io.IOException: java.io.IOException: mac check in GCM failed
    at com.sshtools.common.publickey.OpenSSHPrivateKeyFile.getOpenSSHKeyPair(OpenSSHPrivateKeyFile.java:492)
    at com.sshtools.common.publickey.OpenSSHPrivateKeyFile.toKeyPair(OpenSSHPrivateKeyFile.java:162)
    at com.sshtools.common.publickey.SshKeyUtils.getPrivateKey(SshKeyUtils.java:113)
    at com.sshtools.common.publickey.SshKeyUtils.getPrivateKey(SshKeyUtils.java:91)
    at com.sshtools.common.publickey.SshKeyUtils.getCertificate(SshKeyUtils.java:133)
    at org.test.sftp.sftpclient.<init>(sftpclient.java:112)
    at org.test.sftp.sftpclient.main(sftpclient.java:70)
Caused by: java.io.IOException: mac check in GCM failed
    at com.sshtools.common.ssh.components.jce.AES256Gcm.transform(AES256Gcm.java:119)
    at com.sshtools.common.ssh.components.AbstractSshCipher.transform(AbstractSshCipher.java:100)
    at com.sshtools.common.publickey.OpenSSHPrivateKeyFile.getOpenSSHKeyPair(OpenSSHPrivateKeyFile.java:391)
    ... 6 more
Caused by: javax.crypto.AEADBadTagException: mac check in GCM failed
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source)
    at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2263)
    at com.sshtools.common.ssh.components.jce.AES256Gcm.transform(AES256Gcm.java:109)
    ... 8 more
Exception in thread "main" com.sshtools.common.publickey.InvalidPassphraseException: java.io.IOException: mac check in GCM failed
    at com.sshtools.common.publickey.OpenSSHPrivateKeyFile.toKeyPair(OpenSSHPrivateKeyFile.java:168)
    at com.sshtools.common.publickey.SshKeyUtils.getPrivateKey(SshKeyUtils.java:113)
    at com.sshtools.common.publickey.SshKeyUtils.getPrivateKey(SshKeyUtils.java:91)
    at com.sshtools.common.publickey.SshKeyUtils.getCertificate(SshKeyUtils.java:133)
    at org.test.sftp.sftpclient.<init>(sftpclient.java:112)
    at org.test.sftp.sftpclient.main(sftpclient.java:70)

Specifying an alternative privatekey encryption is possible with later versions of OpenSSH, ssh-keygen man pages state

     -Z cipher
             Specifies the cipher to use for encryption when writing an OpenSSH-format private key file.  The list of available ciphers may be obtained using "ssh -Q cipher".  The default is “aes256-ctr”.

Supported ciphers in OpenSSH_9.6p1, LibreSSL 3.3.6 are

ssh -Q cipher
3des-cbc
aes128-cbc
aes192-cbc
aes256-cbc
aes128-ctr
aes192-ctr
aes256-ctr
aes128-gcm@openssh.com
aes256-gcm@openssh.com
chacha20-poly1305@openssh.com

I have encrypted my private key used in this with command

ssh-keygen -Z aes256-gcm@openssh.com -o -p -f <file>

My understanding on this is limited but issue might be related to https://stackoverflow.com/questions/35558249/aes-gcm-with-bouncycastle-throws-mac-check-in-gcm-failed-when-used-with-iv. Did some digging and found out that https://github.com/sshtools/maverick-synergy/blob/756ca191c3de5703cafdc959fa814348abed5811/maverick-base/src/main/java/com/sshtools/common/publickey/OpenSSHPrivateKeyFile.java#L275 returns value of 16 and https://github.com/sshtools/maverick-synergy/blob/756ca191c3de5703cafdc959fa814348abed5811/maverick-base/src/main/java/com/sshtools/common/publickey/OpenSSHPrivateKeyFile.java#L276 returns value for 24

In ssh-keygen aes256-gcm seems to use IV length of 12 and key length of 32, https://github.com/openssh/openssh-portable/blob/master/cipher.c#L99