Keys.java
/*
* Copyright 2022 The Sigstore Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.sigstore.encryption;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/** For internal use. Key related utility functions. */
public class Keys {
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* Takes a PKIX DER formatted ECDSA public key in bytes and constructs a {@code PublicKey} with
* it.
*
* @param contents the public key bytes
* @return a PublicKey object
* @throws InvalidKeySpecException if the public key material is invalid
*/
public static PublicKey parseEcdsa(byte[] contents) throws InvalidKeySpecException {
return parse(contents, "ECDSA");
}
/**
* Takes a PKIX DER formatted Ed25519 public key in bytes and constructs a {@code PublicKey} with
* it.
*
* @param contents the public key bytes
* @return a PublicKey object
* @throws InvalidKeySpecException if the public key material is invalid
*/
public static PublicKey parseEd25519(byte[] contents) throws InvalidKeySpecException {
return parse(contents, "Ed25519");
}
/**
* Takes a PKIX DER formatted RSA public key in bytes and constructs a {@code PublicKey} with it.
*
* @param contents the public key bytes
* @return a PublicKey object
* @throws InvalidKeySpecException if the public key material is invalid
*/
public static PublicKey parseRsa(byte[] contents) throws InvalidKeySpecException {
return parse(contents, "RSA");
}
/**
* Takes a PKCS1 DER formatted RSA public key in bytes and constructs a {@code PublicKey} with it.
*
* @param contents the public key bytes
* @return a PublicKey object
* @throws InvalidKeySpecException if the public key material is invalid
*/
public static PublicKey parseRsaPkcs1(byte[] contents) throws InvalidKeySpecException {
try {
ASN1Sequence sequence = ASN1Sequence.getInstance(contents);
ASN1Integer modulus = ASN1Integer.getInstance(sequence.getObjectAt(0));
ASN1Integer exponent = ASN1Integer.getInstance(sequence.getObjectAt(1));
RSAPublicKeySpec keySpec =
new RSAPublicKeySpec(modulus.getPositiveValue(), exponent.getPositiveValue());
KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
return factory.generatePublic(keySpec);
} catch (IllegalArgumentException | NullPointerException e) {
throw new InvalidKeySpecException("Failed to parse pkcs1 rsa key", e);
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static PublicKey parse(byte[] contents, String type) throws InvalidKeySpecException {
try {
var keySpec = new X509EncodedKeySpec(contents);
var factory = KeyFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
return factory.generatePublic(keySpec);
} catch (ArrayIndexOutOfBoundsException aoe) {
throw new InvalidKeySpecException(aoe);
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}