Skip to content

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์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

java
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๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ•œ๋‹ค.

java
@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 ํด๋ž˜์Šค๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

java
// 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๋กœ ๋ณ€ํ™˜ํ•  ํ•„์š”๋Š” ์—†์„ ๊ฒƒ ๊ฐ™๋‹ค.

java
// NOTE: AsymmetricCipherKeyPair keyPair
Ed25519PublicKeyParameters publicKeyP = (Ed25519PublicKeyParameters) keyPair.getPublic();
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKeyP);

EdDSA Signatures โ€‹

Curve25519์™€ Curve448๋ฅผ ์‚ฌ์šฉํ•œ EdDSA๋Š” ๊ฐ๊ฐ Ed25519์™€ Ed448 ์ด๋ผ๋Š” ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ํ‘œํ˜„ํ•œ๋‹ค. ์•ž์„œ, PrivateKey์™€ SubjectPublickKeyInfo๋กœ ๋ณ€ํ™˜ํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ X.509 ์ธ์ฆ์„œ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค.

java
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๋ฅผ ๊ฐ€์ง€๋Š” ํ‚ค ํŽ˜์–ด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

java
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("Ed25519", BouncyCastleProvider.PROVIDER_NAME);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

๋” ์ž์„ธํ•œ ์ฝ”๋“œ๋Š” EdDSATest.java์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Released under the MIT License.