微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何使用 Bouncy Castle 创建兼容 OpenSSH 的 ED25519 密钥?

如何解决如何使用 Bouncy Castle 创建兼容 OpenSSH 的 ED25519 密钥?

如何创建可用于 SSH 的 OpenSSH ED25519 私钥?目标是为 OpenSSH 客户端提供与 .ssh/id_ed25519 中相同格式的密钥文件

这是我目前的方法,它不会创建一个兼容的:

import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.params.asymmetricKeyParameter;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import java.io.StringWriter;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;

public class Test {
    static {
        Security.removeProvider("BC");provider
        Security.insertProviderAt(new BouncyCastleProvider(),1);
    }

    public static String createCurve25519PEM() {
        try {
            X9ECParameters curveParams = CustomNamedCurves.getByName("Curve25519");
            ECParameterSpec ecSpec = new ECParameterSpec(curveParams.getCurve(),curveParams.getG(),curveParams.getN(),curveParams.getH(),curveParams.getSeed());
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC",new BouncyCastleProvider());
            kpg.initialize(ecSpec);
            KeyPair keypair = kpg.generateKeyPair();

            asymmetricKeyParameter akp = PrivateKeyFactory.createKey(keypair.getPrivate().getEncoded());
            byte[] content = OpenSSHPrivateKeyUtil.encodePrivateKey(akp);
            PemObject o = new PemObject("OPENSSH PRIVATE KEY",content);
            StringWriter sw = new StringWriter();
            PemWriter w = new PemWriter(sw);
            w.writeObject(o);
            w.close();
            Log.d("createCurve25519PEM","key: " + sw.toString());
            return sw.toString();
        } catch (Exception e) {
            Log.d("createCurve25519PEM",e.toString());
        }
        return null;
    }
}

输出如下:

-----BEGIN OPENSSH PRIVATE KEY-----
MIIBTwIBAQQgA8BjYjSjUgM4PahSZQx3i9DWcEdGiGnBoA0tXCUENzKggeEwgd4C
AQEwKwYHKoZIzj0BAQIgf////////////////////////////////////////+0w
RAQgKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmEkUoUQEIHtCXtCXtCXtCXtC
XtCXtCXtCXtCXtCXtCYLXpx3EMhkBEEEKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
qqqqqqqtJFogrhmhuKCGtOAe3Sx3SNFMkj1Nfm18YbIp6cWifs7T2QIgEAAAAAAA
AAAAAAAAAAAAABTe+d6i95zWWBJjGlz10+0CAQihRANCAARl0Kc+dO0Er1dpu6mh
/lZmTw3/DMKpltzjosX2u7hQswV+U9o0WOYFd1JOqsGdkLfYuGmdZzWdk74dvV1O
+w5T
-----END OPENSSH PRIVATE KEY-----

.. 但不幸的是不被 SSH 接受。

解决方法

以这种方式使用“Curve25519”以X9使用的简短的Weierstrass形式提供给您;这不适用于 Ed25519,它被定义为使用扭曲的爱德华形式。此外,通过 JCA 不幸的 ECParameterSpec 类填充它给出了原始的 X9 定义的“显式”表示,该表示现在已经过时,甚至几乎从未用于确实使用 Weierstrass 曲线的算法。因此,您创建的数据对于 PEM 类型 OPENSSH PRIVATE KEY 不正确;它对 OpenSSL 的“传统”PEM 类型 EC PRIVATE KEY 有效,并且 OpenSSL(它仍然支持但不喜欢“param_enc 显式”)能够使用 that 类型,尽管它不能用于与其他任何东西互操作。

您需要将 JCA 与 算法“ED25519”(不是“EC”“ECDSA”“ECDH”“ECMQV”等都是 X9/SECG)一起使用,如下所示:

    KeyPair pair = KeyPairGenerator.getInstance("ED25519","BC") .generateKeyPair();
    AsymmetricKeyParameter bprv = PrivateKeyFactory.createKey(pair.getPrivate().getEncoded());
    // then proceed as you already have; I have simplified for my test environment
    byte[] oprv = OpenSSHPrivateKeyUtil.encodePrivateKey(bprv);
    PemWriter w = new PemWriter(new OutputStreamWriter(System.out));
    w.writeObject(new PemObject("OPENSSH PRIVATE KEY",oprv)); w.close();

    // BTW if you pass an actual Provider to .getInstance (rather than a String,or letting it search)
    // you don't actually need to have put that Provider in the searchlist
    // Also in Java 15 up you can use the SunEC provider (normally searched by default)
    // but since you still need other Bouncy pieces why bother

或者因为您已经依赖 Bouncy 使用轻量级 API:

    AsymmetricCipherKeyPairGenerator gen = new Ed25519KeyPairGenerator(); 
    gen.init(new KeyGenerationParameters(new SecureRandom(),255));
    AsymmetricKeyParameter bprv = gen.generateKeyPair().getPrivate();
    // ditto

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?