package de.tavolio.realm.key; import de.tavolio.realm.RealmEntity; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; import java.util.Base64; import java.util.NoSuchElementException; import java.util.UUID; @ApplicationScoped public class KeypairService { public static final String EC = "EC"; public static final String P256 = "secp256r1"; @Inject KeypairRepo keypairRepo; @Transactional public void create(RealmEntity realm, String type, String alg) { if ("EC".equals(type)) { KeypairEntity keypair = getKeypair(realm); keypair.setRealm(realm); realm.getKeys().add(keypair); keypairRepo.persist(keypair); return; } throw new NoSuchElementException(); } private KeypairEntity getKeypair(RealmEntity realm) { KeyPair pair = generate(); ECPublicKey publicKey = (ECPublicKey) pair.getPublic(); byte[] xBytes = toFixedLength(publicKey.getW().getAffineX().toByteArray()); byte[] yBytes = toFixedLength(publicKey.getW().getAffineY().toByteArray()); return new KeypairEntity() .setId(UUID.randomUUID().toString()) .setRealm(realm) .setPrivateKey(pair.getPrivate().getEncoded()) .setType("EC") .setUse("sig") .setAlg("ES256") .setCrv("P-256") .setX(Base64.getUrlEncoder().withoutPadding().encodeToString(xBytes)) .setY(Base64.getUrlEncoder().withoutPadding().encodeToString(yBytes)); } private KeyPair generate() { try { KeyPairGenerator generator = KeyPairGenerator.getInstance(EC); generator.initialize(new ECGenParameterSpec(P256)); return generator.generateKeyPair(); } catch (Exception e) { throw new RuntimeException(); } } private byte[] toFixedLength(byte[] input) { if (input.length > 32) { byte[] result = new byte[32]; System.arraycopy(input, input.length - 32, result, 0, 32); return result; } return input; } }