EdDSA
EdDSA(Edwards-curve Digital Signature Algorithm)는 Edwards-Curve
곡선에 의한 전자 서명 알고리즘을 의미한다. 과거에 ED25519에 대해서 정리한 것과 같이 ECDSA와 혼동이 될 수 있다. RFC8410에서는 Internet X.509 Public Key Infrastructure 에서 Ed25519과 같은 Algorithm Identifiers에 대한 표준을 설명하고 있다.
Curve25519 and Curve448 Algorithm Identifiers
BC(Bouncy Castle)의 ECNamedCurveTable.getNames()
에는 기본적인 EC 곡선이 포함되어있고 curve25519
는 CustomNamedCurves에 포함되어 있어 Curve25519 곡선에 대한 X9ECParameters를 아래와 같이 ECParameterSpec으로 변경할 수 있다.
public static AlgorithmParameterSpec curve25519Spec() {
// NOTE: Ed25519 not contains in ECNamedCurveTable.getNames()
X9ECParameters ecP = CustomNamedCurves.getByName("curve25519");
return new ECParameterSpec(ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed());
}
Ed25519 키 페어 생성
Ed25519KeyPairGenerator
와 함께 ECKeyGenerationParameters
를 사용하면 Ed25519 키 페어를 생성할 수 있다. 그런데 이미 Ed25519KeyGenerationParameters를 제공하고 있으므로 굳이 ECParameterSpec를 사용하는 코드를 작성할 필요가 없다. 만약, 굳이 ECParameterSpec으로 ECKeyGenerationParameters를 만들어서 사용하고 싶은 사람들을 위해 예제 코드를 첨부한다.
@Test
void TestKeyPairUsingEd25519Generator() {
Ed25519KeyPairGenerator keyPairGenerator = new Ed25519KeyPairGenerator();
keyPairGenerator.init(new Ed25519KeyGenerationParameters(new SecureRandom()));
AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair();
}
@Test
void TestKeyPairUsingECParams() {
ECParameterSpec curve25519Spec = (ECParameterSpec) curve25519Spec();
ECDomainParameters ecParams = new ECDomainParameters(curve25519Spec.getCurve(), curve25519Spec.getG(), curve25519Spec.getN(), curve25519Spec.getH());
ECKeyGenerationParameters ecKeyGenerationParameters = new ECKeyGenerationParameters(ecParams, new SecureRandom());
Ed25519KeyPairGenerator keyPairGenerator = new Ed25519KeyPairGenerator();
keyPairGenerator.init(ecKeyGenerationParameters);
AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair();
}
Ed25519PrivateKeyParameters를 PrivateKey로 변환
클라이언트의 X.509 인증서를 만드는 경우 서명을 위한 PrivateKey가 필요한데 직접적으로 변환할 수가 없으므로 KeyFactorySpi.Ed25519
와 PrivateKeyInfoFactory
를 사용해서 Ed25519PrivateKeyParameters로 되어있는 비밀키를 PrivateKey 클래스로 변경해야 한다.
// NOTE: AsymmetricCipherKeyPair keyPair
Ed25519PrivateKeyParameters privateKeyP = (Ed25519PrivateKeyParameters) keyPair.getPrivate();
KeyFactorySpi.Ed25519 keyFactory = new KeyFactorySpi.Ed25519();
PrivateKey privateKey = keyFactory.generatePrivate(PrivateKeyInfoFactory.createPrivateKeyInfo(privateKeyP));
공개키를 SubjectPublicKeyInfoFactory로 변환
Ed25519PublicKeyParameters로 되어있는 공개키를 SubjectPublicKeyInfo로 변환하는 것은 SubjectPublicKeyInfoFactory
클래스에서 제공하고 있다. 앞서 비밀키처럼 KeyFactorySpi.Ed25519를 사용해서 PublicKey로 변환할 필요는 없을 것 같다.
// NOTE: AsymmetricCipherKeyPair keyPair
Ed25519PublicKeyParameters publicKeyP = (Ed25519PublicKeyParameters) keyPair.getPublic();
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKeyP);
EdDSA Signatures
Curve25519와 Curve448를 사용한 EdDSA는 각각 Ed25519
와 Ed448
이라는 서명 알고리즘으로 표현한다. 앞서, PrivateKey와 SubjectPublickKeyInfo로 변환한 상태이므로 X.509 인증서를 만드는 것은 어렵지 않을 것이다.
X500Name issuer = new X500Name("CN=Mambo");
BigInteger serialNumber = new BigInteger(128, new SecureRandom());
ZonedDateTime now = ZonedDateTime.now();
Date notBefore = Date.from(now.toInstant());
Date notAfter = Date.from(now.plus(1, ChronoUnit.YEARS).toInstant());
ContentSigner contentSigner = new JcaContentSignerBuilder("Ed25519").setProvider(BouncyCastleProvider.PROVIDER_NAME).build(privateKey);
X509CertificateHolder certificateHolder = new JcaX509v3CertificateBuilder(issuer, serialNumber, notBefore, notAfter, issuer, publicKeyInfo).build(contentSigner);
X509Certificate certificate = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certificateHolder);
certificate.checkValidity(new Date());
KeyPairGeneratorSpi로 Ed25519 키 페어 생성
사실은 BC에서 KeyPairGeneratorSpi를 제공하고 있으므로 아래와 같이 BCEdDSAPrivateKey
와 BCEdDSAPublicKey
를 가지는 키 페어를 생성할 수 있다.
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("Ed25519", BouncyCastleProvider.PROVIDER_NAME);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
더 자세한 코드는 EdDSATest.java에서 확인할 수 있다.