Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2012 The Android Open Source Project
*
* 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 com.android.ide.common.signing;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.utils.ILogger;
import com.android.utils.Pair;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import com.google.common.io.Closeables;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
/**
* A Helper to create and read keystore/keys.
*/
public final class KeystoreHelper {
/**
* Certificate CN value. This is a hard-coded value for the debug key.
* Android Market checks against this value in order to refuse applications signed with
* debug keys.
*/
private static final String CERTIFICATE_DESC = "CN=Android Debug,O=Android,C=US";
/**
* Generated certificate validity.
*/
private static final int DEFAULT_VALIDITY_YEARS = 30;
/**
* Returns the location of the default debug keystore.
* @return The location of the default debug keystore
* @throws AndroidLocationException if the location cannot be computed
*/
@NonNull
public static String defaultDebugKeystoreLocation() throws AndroidLocationException {
//this is guaranteed to either return a non null value (terminated with a platform
// specific separator), or throw.
String folder = AndroidLocation.getFolder();
return folder + "debug.keystore";
}
/**
* Creates a new debug store with the location, keyalias, and passwords specified in the
* config.
* @param storeType an optional type of keystore; if {@code null} the default
* @param storeFile the file where the store should be created
* @param storePassword a password for the key store
* @param keyPassword a password for the key
* @param keyAlias the alias under which the key is stored in the store
* @param logger (not used, kept for backwards compatibility)
* @throws KeytoolException
*/
public static boolean createDebugStore(@Nullable String storeType, @NonNull File storeFile,
@NonNull String storePassword, @NonNull String keyPassword, @NonNull String keyAlias,
@NonNull ILogger logger) throws KeytoolException {
return createNewStore(storeType, storeFile, storePassword, keyPassword, keyAlias,
CERTIFICATE_DESC, DEFAULT_VALIDITY_YEARS);
}
/**
* Creates a new store with a self-signed certificate. The certificate will be valid starting
* from the current date up to the number of years provided.
* @param storeType an optional type of keystore; if {@code null} the default
* @param storeFile the file where the store should be created
* @param storePassword a password for the key store
* @param keyPassword a password for the key
* @param keyAlias the alias under which the key is stored in the store
* @param dn the distinguished name of the owner and issuer of the certificate
* @param validityYears number of years the certificate should be valid
* @throws KeytoolException failed to generate the self-signed certificate or the store
*/
private static boolean createNewStore(
@Nullable String storeType,
@NonNull File storeFile,
@NonNull String storePassword,
@NonNull String keyPassword,
@NonNull String keyAlias,
@NonNull String dn,
int validityYears)
throws KeytoolException {
Preconditions.checkArgument(validityYears > 0, "validityYears (%s) <= 0", validityYears);
String useStoreType = storeType;
if (useStoreType == null) {
useStoreType = KeyStore.getDefaultType();
Verify.verifyNotNull(useStoreType);
}
try {
KeyStore ks = KeyStore.getInstance(useStoreType);
ks.load(null, null);
Pair generated = generateKeyAndCertificate("RSA",
"SHA1withRSA", validityYears, dn);
ks.setKeyEntry(keyAlias, generated.getFirst(), keyPassword.toCharArray(),
new Certificate[]{generated.getSecond()});
FileOutputStream fos = new FileOutputStream(storeFile);
boolean threw = true;
try {
ks.store(fos, storePassword.toCharArray());
threw = false;
} finally {
Closeables.close(fos, threw);
}
} catch (KeytoolException e) {
throw e;
} catch (Exception e) {
throw new KeytoolException("Failed to create keystore.", e);
}
return true;
}
/**
* Returns the CertificateInfo for the given signing configuration.
* @return the certificate info if it could be loaded
* @throws KeytoolException If the password is wrong
* @throws FileNotFoundException If the store file cannot be found
*/
@NonNull
public static CertificateInfo getCertificateInfo(@Nullable String storeType,
@NonNull File storeFile, @NonNull String storePassword, @NonNull String keyPassword,
@NonNull String keyAlias) throws KeytoolException, FileNotFoundException {
try {
KeyStore keyStore = KeyStore.getInstance(storeType != null ?
storeType : KeyStore.getDefaultType());
FileInputStream fis = new FileInputStream(storeFile);
keyStore.load(fis, storePassword.toCharArray());
fis.close();
char[] keyPasswordArray = keyPassword.toCharArray();
PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(
keyAlias, new KeyStore.PasswordProtection(keyPasswordArray));
if (entry == null) {
throw new KeytoolException(
String.format(
"No key with alias '%1$s' found in keystore %2$s",
keyAlias,
storeFile.getAbsolutePath()));
}
return new CertificateInfo(
entry.getPrivateKey(),
(X509Certificate) entry.getCertificate());
} catch (FileNotFoundException e) {
throw e;
} catch (Exception e) {
throw new KeytoolException(
String.format("Failed to read key %1$s from store \"%2$s\": %3$s",
keyAlias, storeFile, e.getMessage()),
e);
}
}
/**
* Generates a key and self-signed certificate pair.
* @param asymmetric the asymmetric encryption algorithm (e.g., {@code RSA})
* @param sign the signature algorithm (e.g., {@code SHA1withRSA})
* @param validityYears number of years the certificate should be valid, must be greater than
* zero
* @param dn the distinguished name of the issuer and owner of the certificate
* @return a pair with the private key and the corresponding certificate
* @throws KeytoolException failed to generate the pair
*/
private static Pair generateKeyAndCertificate(
@NonNull String asymmetric, @NonNull String sign, int validityYears,
@NonNull String dn) throws KeytoolException {
Preconditions.checkArgument(validityYears > 0, "validityYears <= 0");
KeyPair keyPair;
try {
keyPair = KeyPairGenerator.getInstance(asymmetric).generateKeyPair();
} catch (NoSuchAlgorithmException e) {
throw new KeytoolException("Failed to generate key and certificate pair for "
+ "algorithm '" + asymmetric + "'.", e);
}
Date notBefore = new Date(System.currentTimeMillis());
Date notAfter = new Date(System.currentTimeMillis() + validityYears * 365L * 24 * 60 * 60
* 1000);
X500Name issuer = new X500Name(new X500Principal(dn).getName());
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(
keyPair.getPublic().getEncoded());
X509v1CertificateBuilder builder = new X509v1CertificateBuilder(issuer, BigInteger.ONE,
notBefore, notAfter, issuer, publicKeyInfo);
ContentSigner signer;
try {
signer = new JcaContentSignerBuilder(sign).setProvider(
new BouncyCastleProvider()).build(keyPair.getPrivate());
} catch (OperatorCreationException e) {
throw new KeytoolException("Failed to build content signer with signature algorithm '"
+ sign + "'.", e);
}
X509CertificateHolder holder = builder.build(signer);
JcaX509CertificateConverter converter = new JcaX509CertificateConverter()
.setProvider(new BouncyCastleProvider());
X509Certificate certificate;
try {
certificate = converter.getCertificate(holder);
} catch (CertificateException e) {
throw new KeytoolException("Failed to obtain the self-signed certificate.", e);
}
return Pair.of(keyPair.getPrivate(), certificate);
}
}