bring up "gradle pack" and "gradle unpack"
add boot_signer, mkbootimg and dependenciespull/1/head
parent
41ef4cf147
commit
494191bb37
@ -0,0 +1,14 @@
|
||||
apply plugin: 'java'
|
||||
|
||||
jar() {
|
||||
manifest {
|
||||
attributes 'Implementation-Title': 'Gradle Quickstart',
|
||||
'Main-Class': 'com.android.verity.BootSignature'
|
||||
}
|
||||
from {configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }} //pack dependent jar
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':bouncycastle:bcpkix')
|
||||
compile project(':bouncycastle:bcprov')
|
||||
}
|
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.verity;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.util.Arrays;
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1Object;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1OctetString;
|
||||
import org.bouncycastle.asn1.ASN1Primitive;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.DERPrintableString;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.util.ASN1Dump;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
/**
|
||||
* AndroidVerifiedBootSignature DEFINITIONS ::=
|
||||
* BEGIN
|
||||
* formatVersion ::= INTEGER
|
||||
* certificate ::= Certificate
|
||||
* algorithmIdentifier ::= SEQUENCE {
|
||||
* algorithm OBJECT IDENTIFIER,
|
||||
* parameters ANY DEFINED BY algorithm OPTIONAL
|
||||
* }
|
||||
* authenticatedAttributes ::= SEQUENCE {
|
||||
* target CHARACTER STRING,
|
||||
* length INTEGER
|
||||
* }
|
||||
* signature ::= OCTET STRING
|
||||
* END
|
||||
*/
|
||||
|
||||
public class BootSignature extends ASN1Object
|
||||
{
|
||||
private ASN1Integer formatVersion;
|
||||
private ASN1Encodable certificate;
|
||||
private AlgorithmIdentifier algorithmIdentifier;
|
||||
private DERPrintableString target;
|
||||
private ASN1Integer length;
|
||||
private DEROctetString signature;
|
||||
private PublicKey publicKey;
|
||||
|
||||
private static final int FORMAT_VERSION = 1;
|
||||
|
||||
/**
|
||||
* Initializes the object for signing an image file
|
||||
* @param target Target name, included in the signed data
|
||||
* @param length Length of the image, included in the signed data
|
||||
*/
|
||||
public BootSignature(String target, int length) {
|
||||
this.formatVersion = new ASN1Integer(FORMAT_VERSION);
|
||||
this.target = new DERPrintableString(target);
|
||||
this.length = new ASN1Integer(length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the object for verifying a signed image file
|
||||
* @param signature Signature footer
|
||||
*/
|
||||
public BootSignature(byte[] signature)
|
||||
throws Exception {
|
||||
ASN1InputStream stream = new ASN1InputStream(signature);
|
||||
ASN1Sequence sequence = (ASN1Sequence) stream.readObject();
|
||||
|
||||
formatVersion = (ASN1Integer) sequence.getObjectAt(0);
|
||||
if (formatVersion.getValue().intValue() != FORMAT_VERSION) {
|
||||
throw new IllegalArgumentException("Unsupported format version");
|
||||
}
|
||||
|
||||
certificate = sequence.getObjectAt(1);
|
||||
byte[] encoded = ((ASN1Object) certificate).getEncoded();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
|
||||
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
X509Certificate c = (X509Certificate) cf.generateCertificate(bis);
|
||||
publicKey = c.getPublicKey();
|
||||
|
||||
ASN1Sequence algId = (ASN1Sequence) sequence.getObjectAt(2);
|
||||
algorithmIdentifier = new AlgorithmIdentifier(
|
||||
(ASN1ObjectIdentifier) algId.getObjectAt(0));
|
||||
|
||||
ASN1Sequence attrs = (ASN1Sequence) sequence.getObjectAt(3);
|
||||
target = (DERPrintableString) attrs.getObjectAt(0);
|
||||
length = (ASN1Integer) attrs.getObjectAt(1);
|
||||
|
||||
this.signature = (DEROctetString) sequence.getObjectAt(4);
|
||||
}
|
||||
|
||||
public ASN1Object getAuthenticatedAttributes() {
|
||||
ASN1EncodableVector attrs = new ASN1EncodableVector();
|
||||
attrs.add(target);
|
||||
attrs.add(length);
|
||||
return new DERSequence(attrs);
|
||||
}
|
||||
|
||||
public byte[] getEncodedAuthenticatedAttributes() throws IOException {
|
||||
return getAuthenticatedAttributes().getEncoded();
|
||||
}
|
||||
|
||||
public AlgorithmIdentifier getAlgorithmIdentifier() {
|
||||
return algorithmIdentifier;
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
return signature.getOctets();
|
||||
}
|
||||
|
||||
public void setSignature(byte[] sig, AlgorithmIdentifier algId) {
|
||||
algorithmIdentifier = algId;
|
||||
signature = new DEROctetString(sig);
|
||||
}
|
||||
|
||||
public void setCertificate(X509Certificate cert)
|
||||
throws Exception, IOException, CertificateEncodingException {
|
||||
ASN1InputStream s = new ASN1InputStream(cert.getEncoded());
|
||||
certificate = s.readObject();
|
||||
}
|
||||
|
||||
public byte[] generateSignableImage(byte[] image) throws IOException {
|
||||
byte[] attrs = getEncodedAuthenticatedAttributes();
|
||||
byte[] signable = Arrays.copyOf(image, image.length + attrs.length);
|
||||
for (int i=0; i < attrs.length; i++) {
|
||||
signable[i+image.length] = attrs[i];
|
||||
}
|
||||
return signable;
|
||||
}
|
||||
|
||||
public byte[] sign(byte[] image, PrivateKey key) throws Exception {
|
||||
byte[] signable = generateSignableImage(image);
|
||||
return Utils.sign(key, signable);
|
||||
}
|
||||
|
||||
public boolean verify(byte[] image) throws Exception {
|
||||
if (length.getValue().intValue() != image.length) {
|
||||
throw new IllegalArgumentException("Invalid image length");
|
||||
}
|
||||
|
||||
byte[] signable = generateSignableImage(image);
|
||||
return Utils.verify(publicKey, signable, signature.getOctets(),
|
||||
algorithmIdentifier);
|
||||
}
|
||||
|
||||
public ASN1Primitive toASN1Primitive() {
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
v.add(formatVersion);
|
||||
v.add(certificate);
|
||||
v.add(algorithmIdentifier);
|
||||
v.add(getAuthenticatedAttributes());
|
||||
v.add(signature);
|
||||
return new DERSequence(v);
|
||||
}
|
||||
|
||||
public static int getSignableImageSize(byte[] data) throws Exception {
|
||||
if (!Arrays.equals(Arrays.copyOfRange(data, 0, 8),
|
||||
"ANDROID!".getBytes("US-ASCII"))) {
|
||||
throw new IllegalArgumentException("Invalid image header: missing magic");
|
||||
}
|
||||
|
||||
ByteBuffer image = ByteBuffer.wrap(data);
|
||||
image.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
image.getLong(); // magic
|
||||
int kernelSize = image.getInt();
|
||||
image.getInt(); // kernel_addr
|
||||
int ramdskSize = image.getInt();
|
||||
image.getInt(); // ramdisk_addr
|
||||
int secondSize = image.getInt();
|
||||
image.getLong(); // second_addr + tags_addr
|
||||
int pageSize = image.getInt();
|
||||
|
||||
int length = pageSize // include the page aligned image header
|
||||
+ ((kernelSize + pageSize - 1) / pageSize) * pageSize
|
||||
+ ((ramdskSize + pageSize - 1) / pageSize) * pageSize
|
||||
+ ((secondSize + pageSize - 1) / pageSize) * pageSize;
|
||||
|
||||
length = ((length + pageSize - 1) / pageSize) * pageSize;
|
||||
|
||||
if (length <= 0) {
|
||||
throw new IllegalArgumentException("Invalid image header: invalid length");
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
public static void doSignature( String target,
|
||||
String imagePath,
|
||||
String keyPath,
|
||||
String certPath,
|
||||
String outPath) throws Exception {
|
||||
|
||||
byte[] image = Utils.read(imagePath);
|
||||
int signableSize = getSignableImageSize(image);
|
||||
|
||||
if (signableSize < image.length) {
|
||||
System.err.println("NOTE: truncating file " + imagePath +
|
||||
" from " + image.length + " to " + signableSize + " bytes");
|
||||
image = Arrays.copyOf(image, signableSize);
|
||||
} else if (signableSize > image.length) {
|
||||
throw new IllegalArgumentException("Invalid image: too short, expected " +
|
||||
signableSize + " bytes");
|
||||
}
|
||||
|
||||
BootSignature bootsig = new BootSignature(target, image.length);
|
||||
|
||||
X509Certificate cert = Utils.loadPEMCertificate(certPath);
|
||||
bootsig.setCertificate(cert);
|
||||
|
||||
PrivateKey key = Utils.loadDERPrivateKeyFromFile(keyPath);
|
||||
bootsig.setSignature(bootsig.sign(image, key),
|
||||
Utils.getSignatureAlgorithmIdentifier(key));
|
||||
|
||||
byte[] encoded_bootsig = bootsig.getEncoded();
|
||||
byte[] image_with_metadata = Arrays.copyOf(image, image.length + encoded_bootsig.length);
|
||||
|
||||
System.arraycopy(encoded_bootsig, 0, image_with_metadata,
|
||||
image.length, encoded_bootsig.length);
|
||||
|
||||
Utils.write(image_with_metadata, outPath);
|
||||
}
|
||||
|
||||
public static void verifySignature(String imagePath) throws Exception {
|
||||
byte[] image = Utils.read(imagePath);
|
||||
int signableSize = getSignableImageSize(image);
|
||||
|
||||
if (signableSize >= image.length) {
|
||||
throw new IllegalArgumentException("Invalid image: not signed");
|
||||
}
|
||||
|
||||
byte[] signature = Arrays.copyOfRange(image, signableSize, image.length);
|
||||
BootSignature bootsig = new BootSignature(signature);
|
||||
|
||||
try {
|
||||
if (bootsig.verify(Arrays.copyOf(image, signableSize))) {
|
||||
System.err.println("Signature is VALID");
|
||||
System.exit(0);
|
||||
} else {
|
||||
System.err.println("Signature is INVALID");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/* Example usage for signing a boot image using dev keys:
|
||||
java -cp \
|
||||
../../../out/host/common/obj/JAVA_LIBRARIES/BootSignature_intermediates/ \
|
||||
classes/com.android.verity.BootSignature \
|
||||
/boot \
|
||||
../../../out/target/product/$PRODUCT/boot.img \
|
||||
../../../build/target/product/security/verity.pk8 \
|
||||
../../../build/target/product/security/verity.x509.pem \
|
||||
/tmp/boot.img.signed
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
if ("-verify".equals(args[0])) {
|
||||
/* args[1] is the path to a signed boot image */
|
||||
verifySignature(args[1]);
|
||||
} else {
|
||||
/* args[0] is the target name, typically /boot
|
||||
args[1] is the path to a boot image to sign
|
||||
args[2] is the path to a private key
|
||||
args[3] is the path to the matching public key certificate
|
||||
args[4] is the path where to output the signed boot image
|
||||
*/
|
||||
doSignature(args[0], args[1], args[2], args[3], args[4]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.verity;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.io.File;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.Console;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.security.Signature;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.ECPrivateKeySpec;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.EncryptedPrivateKeyInfo;
|
||||
import javax.crypto.SecretKeyFactory;
|
||||
import javax.crypto.spec.PBEKeySpec;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
|
||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
public class Utils {
|
||||
|
||||
private static final Map<String, String> ID_TO_ALG;
|
||||
private static final Map<String, String> ALG_TO_ID;
|
||||
|
||||
static {
|
||||
ID_TO_ALG = new HashMap<String, String>();
|
||||
ALG_TO_ID = new HashMap<String, String>();
|
||||
|
||||
ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA256.getId(), "SHA256withECDSA");
|
||||
ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA384.getId(), "SHA384withECDSA");
|
||||
ID_TO_ALG.put(X9ObjectIdentifiers.ecdsa_with_SHA512.getId(), "SHA512withECDSA");
|
||||
ID_TO_ALG.put(PKCSObjectIdentifiers.sha1WithRSAEncryption.getId(), "SHA1withRSA");
|
||||
ID_TO_ALG.put(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), "SHA256withRSA");
|
||||
ID_TO_ALG.put(PKCSObjectIdentifiers.sha512WithRSAEncryption.getId(), "SHA512withRSA");
|
||||
|
||||
ALG_TO_ID.put("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256.getId());
|
||||
ALG_TO_ID.put("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384.getId());
|
||||
ALG_TO_ID.put("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512.getId());
|
||||
ALG_TO_ID.put("SHA1withRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption.getId());
|
||||
ALG_TO_ID.put("SHA256withRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption.getId());
|
||||
ALG_TO_ID.put("SHA512withRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption.getId());
|
||||
}
|
||||
|
||||
private static void loadProviderIfNecessary(String providerClassName) {
|
||||
if (providerClassName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Class<?> klass;
|
||||
try {
|
||||
final ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
|
||||
if (sysLoader != null) {
|
||||
klass = sysLoader.loadClass(providerClassName);
|
||||
} else {
|
||||
klass = Class.forName(providerClassName);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
Constructor<?> constructor = null;
|
||||
for (Constructor<?> c : klass.getConstructors()) {
|
||||
if (c.getParameterTypes().length == 0) {
|
||||
constructor = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (constructor == null) {
|
||||
System.err.println("No zero-arg constructor found for " + providerClassName);
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
final Object o;
|
||||
try {
|
||||
o = constructor.newInstance();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
if (!(o instanceof Provider)) {
|
||||
System.err.println("Not a Provider class: " + providerClassName);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Security.insertProviderAt((Provider) o, 1);
|
||||
}
|
||||
|
||||
static byte[] pemToDer(String pem) throws Exception {
|
||||
pem = pem.replaceAll("^-.*", "");
|
||||
String base64_der = pem.replaceAll("-.*$", "");
|
||||
return Base64.decode(base64_der);
|
||||
}
|
||||
|
||||
private static PKCS8EncodedKeySpec decryptPrivateKey(byte[] encryptedPrivateKey)
|
||||
throws GeneralSecurityException {
|
||||
EncryptedPrivateKeyInfo epkInfo;
|
||||
try {
|
||||
epkInfo = new EncryptedPrivateKeyInfo(encryptedPrivateKey);
|
||||
} catch (IOException ex) {
|
||||
// Probably not an encrypted key.
|
||||
return null;
|
||||
}
|
||||
|
||||
char[] password = System.console().readPassword("Password for the private key file: ");
|
||||
|
||||
SecretKeyFactory skFactory = SecretKeyFactory.getInstance(epkInfo.getAlgName());
|
||||
Key key = skFactory.generateSecret(new PBEKeySpec(password));
|
||||
Arrays.fill(password, '\0');
|
||||
|
||||
Cipher cipher = Cipher.getInstance(epkInfo.getAlgName());
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, epkInfo.getAlgParameters());
|
||||
|
||||
try {
|
||||
return epkInfo.getKeySpec(cipher);
|
||||
} catch (InvalidKeySpecException ex) {
|
||||
System.err.println("Password may be bad.");
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
static PrivateKey loadDERPrivateKey(byte[] der) throws Exception {
|
||||
PKCS8EncodedKeySpec spec = decryptPrivateKey(der);
|
||||
|
||||
if (spec == null) {
|
||||
spec = new PKCS8EncodedKeySpec(der);
|
||||
}
|
||||
|
||||
ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded()));
|
||||
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
|
||||
String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
|
||||
|
||||
return KeyFactory.getInstance(algOid).generatePrivate(spec);
|
||||
}
|
||||
|
||||
static PrivateKey loadPEMPrivateKey(byte[] pem) throws Exception {
|
||||
byte[] der = pemToDer(new String(pem));
|
||||
return loadDERPrivateKey(der);
|
||||
}
|
||||
|
||||
static PrivateKey loadPEMPrivateKeyFromFile(String keyFname) throws Exception {
|
||||
return loadPEMPrivateKey(read(keyFname));
|
||||
}
|
||||
|
||||
static PrivateKey loadDERPrivateKeyFromFile(String keyFname) throws Exception {
|
||||
return loadDERPrivateKey(read(keyFname));
|
||||
}
|
||||
|
||||
static PublicKey loadDERPublicKey(byte[] der) throws Exception {
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(der);
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
return factory.generatePublic(publicKeySpec);
|
||||
}
|
||||
|
||||
static PublicKey loadPEMPublicKey(byte[] pem) throws Exception {
|
||||
byte[] der = pemToDer(new String(pem));
|
||||
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(der);
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
return factory.generatePublic(publicKeySpec);
|
||||
}
|
||||
|
||||
static PublicKey loadPEMPublicKeyFromFile(String keyFname) throws Exception {
|
||||
return loadPEMPublicKey(read(keyFname));
|
||||
}
|
||||
|
||||
static PublicKey loadDERPublicKeyFromFile(String keyFname) throws Exception {
|
||||
return loadDERPublicKey(read(keyFname));
|
||||
}
|
||||
|
||||
static X509Certificate loadPEMCertificate(String fname) throws Exception {
|
||||
try (FileInputStream fis = new FileInputStream(fname)) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) cf.generateCertificate(fis);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSignatureAlgorithm(Key key) throws Exception {
|
||||
if ("EC".equals(key.getAlgorithm())) {
|
||||
int curveSize;
|
||||
KeyFactory factory = KeyFactory.getInstance("EC");
|
||||
|
||||
if (key instanceof PublicKey) {
|
||||
ECPublicKeySpec spec = factory.getKeySpec(key, ECPublicKeySpec.class);
|
||||
curveSize = spec.getParams().getCurve().getField().getFieldSize();
|
||||
} else if (key instanceof PrivateKey) {
|
||||
ECPrivateKeySpec spec = factory.getKeySpec(key, ECPrivateKeySpec.class);
|
||||
curveSize = spec.getParams().getCurve().getField().getFieldSize();
|
||||
} else {
|
||||
throw new InvalidKeySpecException();
|
||||
}
|
||||
|
||||
if (curveSize <= 256) {
|
||||
return "SHA256withECDSA";
|
||||
} else if (curveSize <= 384) {
|
||||
return "SHA384withECDSA";
|
||||
} else {
|
||||
return "SHA512withECDSA";
|
||||
}
|
||||
} else if ("RSA".equals(key.getAlgorithm())) {
|
||||
return "SHA256withRSA";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm());
|
||||
}
|
||||
}
|
||||
|
||||
static AlgorithmIdentifier getSignatureAlgorithmIdentifier(Key key) throws Exception {
|
||||
String id = ALG_TO_ID.get(getSignatureAlgorithm(key));
|
||||
|
||||
if (id == null) {
|
||||
throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm());
|
||||
}
|
||||
|
||||
return new AlgorithmIdentifier(new ASN1ObjectIdentifier(id));
|
||||
}
|
||||
|
||||
static boolean verify(PublicKey key, byte[] input, byte[] signature,
|
||||
AlgorithmIdentifier algId) throws Exception {
|
||||
String algName = ID_TO_ALG.get(algId.getObjectId().getId());
|
||||
|
||||
if (algName == null) {
|
||||
throw new IllegalArgumentException("Unsupported algorithm " + algId.getObjectId());
|
||||
}
|
||||
|
||||
Signature verifier = Signature.getInstance(algName);
|
||||
verifier.initVerify(key);
|
||||
verifier.update(input);
|
||||
|
||||
return verifier.verify(signature);
|
||||
}
|
||||
|
||||
static byte[] sign(PrivateKey privateKey, byte[] input) throws Exception {
|
||||
Signature signer = Signature.getInstance(getSignatureAlgorithm(privateKey));
|
||||
signer.initSign(privateKey);
|
||||
signer.update(input);
|
||||
return signer.sign();
|
||||
}
|
||||
|
||||
static byte[] read(String fname) throws Exception {
|
||||
long offset = 0;
|
||||
File f = new File(fname);
|
||||
long length = f.length();
|
||||
byte[] image = new byte[(int)length];
|
||||
FileInputStream fis = new FileInputStream(f);
|
||||
while (offset < length) {
|
||||
offset += fis.read(image, (int)offset, (int)(length - offset));
|
||||
}
|
||||
fis.close();
|
||||
return image;
|
||||
}
|
||||
|
||||
static void write(byte[] data, String fname) throws Exception{
|
||||
FileOutputStream out = new FileOutputStream(fname);
|
||||
out.write(data);
|
||||
out.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.verity;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Security;
|
||||
import java.security.cert.X509Certificate;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
public class VeritySigner {
|
||||
|
||||
private static void usage() {
|
||||
System.err.println("usage: VeritySigner <contentfile> <key.pk8> " +
|
||||
"<sigfile> | <contentfile> <certificate.x509.pem> <sigfile> " +
|
||||
"-verify");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length < 3) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
byte[] content = Utils.read(args[0]);
|
||||
|
||||
if (args.length > 3 && "-verify".equals(args[3])) {
|
||||
X509Certificate cert = Utils.loadPEMCertificate(args[1]);
|
||||
PublicKey publicKey = cert.getPublicKey();
|
||||
|
||||
byte[] signature = Utils.read(args[2]);
|
||||
|
||||
try {
|
||||
if (Utils.verify(publicKey, content, signature,
|
||||
Utils.getSignatureAlgorithmIdentifier(publicKey))) {
|
||||
System.err.println("Signature is VALID");
|
||||
System.exit(0);
|
||||
} else {
|
||||
System.err.println("Signature is INVALID");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
System.exit(1);
|
||||
} else {
|
||||
PrivateKey privateKey = Utils.loadDERPrivateKey(Utils.read(args[1]));
|
||||
byte[] signature = Utils.sign(privateKey, content);
|
||||
Utils.write(signature, args[2]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
include 'bouncycastle:bcpkix'
|
||||
include 'bouncycastle:bcprov'
|
||||
include 'boot_signer'
|
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mincrypt/dsa_sig.h"
|
||||
#include "mincrypt/p256.h"
|
||||
|
||||
/**
|
||||
* Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
|
||||
*/
|
||||
static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
|
||||
int src_len) {
|
||||
int dst_offset;
|
||||
while (*src == '\0' && src_len > 0) {
|
||||
src++;
|
||||
src_len--;
|
||||
}
|
||||
if (src_len > P256_NBYTES || src_len < 1) {
|
||||
return 0;
|
||||
}
|
||||
dst_offset = P256_NBYTES - src_len;
|
||||
memset(dst, 0, dst_offset);
|
||||
memcpy(dst + dst_offset, src, src_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks the ASN.1 DSA signature sequence.
|
||||
*/
|
||||
int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
|
||||
/*
|
||||
* Structure is:
|
||||
* 0x30 0xNN SEQUENCE + s_length
|
||||
* 0x02 0xNN INTEGER + r_length
|
||||
* 0xAA 0xBB .. r_length bytes of "r" (offset 4)
|
||||
* 0x02 0xNN INTEGER + s_length
|
||||
* 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len)
|
||||
*/
|
||||
int seq_len;
|
||||
unsigned char r_bytes[P256_NBYTES];
|
||||
unsigned char s_bytes[P256_NBYTES];
|
||||
int r_len;
|
||||
int s_len;
|
||||
|
||||
memset(r_bytes, 0, sizeof(r_bytes));
|
||||
memset(s_bytes, 0, sizeof(s_bytes));
|
||||
|
||||
/*
|
||||
* Must have at least:
|
||||
* 2 bytes sequence header and length
|
||||
* 2 bytes R integer header and length
|
||||
* 1 byte of R
|
||||
* 2 bytes S integer header and length
|
||||
* 1 byte of S
|
||||
*
|
||||
* 8 bytes total
|
||||
*/
|
||||
if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_len = sig[1];
|
||||
if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r_len = sig[3];
|
||||
/*
|
||||
* Must have at least:
|
||||
* 2 bytes for R header and length
|
||||
* 2 bytes S integer header and length
|
||||
* 1 byte of S
|
||||
*/
|
||||
if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
|
||||
return 0;
|
||||
}
|
||||
s_len = sig[5 + r_len];
|
||||
|
||||
/**
|
||||
* Must have:
|
||||
* 2 bytes for R header and length
|
||||
* r_len bytes for R
|
||||
* 2 bytes S integer header and length
|
||||
*/
|
||||
if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
|
||||
* a correctly-sized buffer and that the resulting integer isn't too large.
|
||||
*/
|
||||
if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
|
||||
|| !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p256_from_bin(r_bytes, r_int);
|
||||
p256_from_bin(s_bytes, s_int);
|
||||
|
||||
return 1;
|
||||
}
|
@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// This is an implementation of the P256 elliptic curve group. It's written to
|
||||
// be portable 32-bit, although it's still constant-time.
|
||||
//
|
||||
// WARNING: Implementing these functions in a constant-time manner is far from
|
||||
// obvious. Be careful when touching this code.
|
||||
//
|
||||
// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mincrypt/p256.h"
|
||||
|
||||
const p256_int SECP256r1_n = // curve order
|
||||
{{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
|
||||
|
||||
const p256_int SECP256r1_p = // curve field size
|
||||
{{-1, -1, -1, 0, 0, 0, 1, -1 }};
|
||||
|
||||
const p256_int SECP256r1_b = // curve b
|
||||
{{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
|
||||
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
|
||||
|
||||
void p256_init(p256_int* a) {
|
||||
memset(a, 0, sizeof(*a));
|
||||
}
|
||||
|
||||
void p256_clear(p256_int* a) { p256_init(a); }
|
||||
|
||||
int p256_get_bit(const p256_int* scalar, int bit) {
|
||||
return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
|
||||
>> (bit & (P256_BITSPERDIGIT - 1))) & 1;
|
||||
}
|
||||
|
||||
int p256_is_zero(const p256_int* a) {
|
||||
int i, result = 0;
|
||||
for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
|
||||
return !result;
|
||||
}
|
||||
|
||||
// top, c[] += a[] * b
|
||||
// Returns new top
|
||||
static p256_digit mulAdd(const p256_int* a,
|
||||
p256_digit b,
|
||||
p256_digit top,
|
||||
p256_digit* c) {
|
||||
int i;
|
||||
p256_ddigit carry = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += *c;
|
||||
carry += (p256_ddigit)P256_DIGIT(a, i) * b;
|
||||
*c++ = (p256_digit)carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return top + (p256_digit)carry;
|
||||
}
|
||||
|
||||
// top, c[] -= top_a, a[]
|
||||
static p256_digit subTop(p256_digit top_a,
|
||||
const p256_digit* a,
|
||||
p256_digit top_c,
|
||||
p256_digit* c) {
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += *c;
|
||||
borrow -= *a++;
|
||||
*c++ = (p256_digit)borrow;
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
borrow += top_c;
|
||||
borrow -= top_a;
|
||||
top_c = (p256_digit)borrow;
|
||||
assert((borrow >> P256_BITSPERDIGIT) == 0);
|
||||
return top_c;
|
||||
}
|
||||
|
||||
// top, c[] -= MOD[] & mask (0 or -1)
|
||||
// returns new top.
|
||||
static p256_digit subM(const p256_int* MOD,
|
||||
p256_digit top,
|
||||
p256_digit* c,
|
||||
p256_digit mask) {
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += *c;
|
||||
borrow -= P256_DIGIT(MOD, i) & mask;
|
||||
*c++ = (p256_digit)borrow;
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return top + (p256_digit)borrow;
|
||||
}
|
||||
|
||||
// top, c[] += MOD[] & mask (0 or -1)
|
||||
// returns new top.
|
||||
static p256_digit addM(const p256_int* MOD,
|
||||
p256_digit top,
|
||||
p256_digit* c,
|
||||
p256_digit mask) {
|
||||
int i;
|
||||
p256_ddigit carry = 0;
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += *c;
|
||||
carry += P256_DIGIT(MOD, i) & mask;
|
||||
*c++ = (p256_digit)carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return top + (p256_digit)carry;
|
||||
}
|
||||
|
||||
// c = a * b mod MOD. c can be a and/or b.
|
||||
void p256_modmul(const p256_int* MOD,
|
||||
const p256_int* a,
|
||||
const p256_digit top_b,
|
||||
const p256_int* b,
|
||||
p256_int* c) {
|
||||
p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
|
||||
p256_digit top = 0;
|
||||
int i;
|
||||
|
||||
// Multiply/add into tmp.
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
if (i) tmp[i + P256_NDIGITS - 1] = top;
|
||||
top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
|
||||
}
|
||||
|
||||
// Multiply/add top digit
|
||||
tmp[i + P256_NDIGITS - 1] = top;
|
||||
top = mulAdd(a, top_b, 0, tmp + i);
|
||||
|
||||
// Reduce tmp, digit by digit.
|
||||
for (; i >= 0; --i) {
|
||||
p256_digit reducer[P256_NDIGITS] = { 0 };
|
||||
p256_digit top_reducer;
|
||||
|
||||
// top can be any value at this point.
|
||||
// Guestimate reducer as top * MOD, since msw of MOD is -1.
|
||||
top_reducer = mulAdd(MOD, top, 0, reducer);
|
||||
|
||||
// Subtract reducer from top | tmp.
|
||||
top = subTop(top_reducer, reducer, top, tmp + i);
|
||||
|
||||
// top is now either 0 or 1. Make it 0, fixed-timing.
|
||||
assert(top <= 1);
|
||||
|
||||
top = subM(MOD, top, tmp + i, ~(top - 1));
|
||||
|
||||
assert(top == 0);
|
||||
|
||||
// We have now reduced the top digit off tmp. Fetch new top digit.
|
||||
top = tmp[i + P256_NDIGITS - 1];
|
||||
}
|
||||
|
||||
// tmp might still be larger than MOD, yet same bit length.
|
||||
// Make sure it is less, fixed-timing.
|
||||
addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
|
||||
|
||||
memcpy(c, tmp, P256_NBYTES);
|
||||
}
|
||||
int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
|
||||
int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
|
||||
|
||||
p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
|
||||
int i;
|
||||
p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
|
||||
|
||||
n %= P256_BITSPERDIGIT;
|
||||
for (i = P256_NDIGITS - 1; i > 0; --i) {
|
||||
p256_digit accu = (P256_DIGIT(a, i) << n);
|
||||
accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
|
||||
P256_DIGIT(b, i) = accu;
|
||||
}
|
||||
P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
|
||||
|
||||
top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
void p256_shr(const p256_int* a, int n, p256_int* b) {
|
||||
int i;
|
||||
|
||||
n %= P256_BITSPERDIGIT;
|
||||
for (i = 0; i < P256_NDIGITS - 1; ++i) {
|
||||
p256_digit accu = (P256_DIGIT(a, i) >> n);
|
||||
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
|
||||
P256_DIGIT(b, i) = accu;
|
||||
}
|
||||
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
|
||||
}
|
||||
|
||||
static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS - 1; ++i) {
|
||||
p256_digit accu = (P256_DIGIT(a, i) >> 1);
|
||||
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
|
||||
P256_DIGIT(b, i) = accu;
|
||||
}
|
||||
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
|
||||
(highbit << (P256_BITSPERDIGIT - 1));
|
||||
}
|
||||
|
||||
// Return -1, 0, 1 for a < b, a == b or a > b respectively.
|
||||
int p256_cmp(const p256_int* a, const p256_int* b) {
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
p256_digit notzero = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
|
||||
// Track whether any result digit is ever not zero.
|
||||
// Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
|
||||
notzero |= !!((p256_digit)borrow);
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int)borrow | notzero;
|
||||
}
|
||||
|
||||
// c = a - b. Returns borrow: 0 or -1.
|
||||
int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
|
||||
if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int)borrow;
|
||||
}
|
||||
|
||||
// c = a + b. Returns carry: 0 or 1.
|
||||
int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
|
||||
int i;
|
||||
p256_ddigit carry = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
|
||||
if (c) P256_DIGIT(c, i) = (p256_digit)carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int)carry;
|
||||
}
|
||||
|
||||
// b = a + d. Returns carry, 0 or 1.
|
||||
int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
|
||||
int i;
|
||||
p256_ddigit carry = d;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += (p256_ddigit)P256_DIGIT(a, i);
|
||||
if (b) P256_DIGIT(b, i) = (p256_digit)carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int)carry;
|
||||
}
|
||||
|
||||
// b = 1/a mod MOD, binary euclid.
|
||||
void p256_modinv_vartime(const p256_int* MOD,
|
||||
const p256_int* a,
|
||||
p256_int* b) {
|
||||
p256_int R = P256_ZERO;
|
||||
p256_int S = P256_ONE;
|
||||
p256_int U = *MOD;
|
||||
p256_int V = *a;
|
||||
|
||||
for (;;) {
|
||||
if (p256_is_even(&U)) {
|
||||
p256_shr1(&U, 0, &U);
|
||||
if (p256_is_even(&R)) {
|
||||
p256_shr1(&R, 0, &R);
|
||||
} else {
|
||||
// R = (R+MOD)/2
|
||||
p256_shr1(&R, p256_add(&R, MOD, &R), &R);
|
||||
}
|
||||
} else if (p256_is_even(&V)) {
|
||||
p256_shr1(&V, 0, &V);
|
||||
if (p256_is_even(&S)) {
|
||||
p256_shr1(&S, 0, &S);
|
||||
} else {
|
||||
// S = (S+MOD)/2
|
||||
p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
|
||||
}
|
||||
} else { // U,V both odd.
|
||||
if (!p256_sub(&V, &U, NULL)) {
|
||||
p256_sub(&V, &U, &V);
|
||||
if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
|
||||
if (p256_is_zero(&V)) break; // done.
|
||||
} else {
|
||||
p256_sub(&U, &V, &U);
|
||||
if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p256_mod(MOD, &R, b);
|
||||
}
|
||||
|
||||
void p256_mod(const p256_int* MOD,
|
||||
const p256_int* in,
|
||||
p256_int* out) {
|
||||
if (out != in) *out = *in;
|
||||
addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
|
||||
}
|
||||
|
||||
// Verify y^2 == x^3 - 3x + b mod p
|
||||
// and 0 < x < p and 0 < y < p
|
||||
int p256_is_valid_point(const p256_int* x, const p256_int* y) {
|
||||
p256_int y2, x3;
|
||||
|
||||
if (p256_cmp(&SECP256r1_p, x) <= 0 ||
|
||||
p256_cmp(&SECP256r1_p, y) <= 0 ||
|
||||
p256_is_zero(x) ||
|
||||
p256_is_zero(y)) return 0;
|
||||
|
||||
p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2
|
||||
|
||||
p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2
|
||||
p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3
|
||||
if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x
|
||||
if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x
|
||||
if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x
|
||||
if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b
|
||||
p256_sub(&x3, &SECP256r1_p, &x3);
|
||||
|
||||
return p256_cmp(&y2, &x3) == 0;
|
||||
}
|
||||
|
||||
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
|
||||
int i;
|
||||
const uint8_t* p = &src[0];
|
||||
|
||||
for (i = P256_NDIGITS - 1; i >= 0; --i) {
|
||||
P256_DIGIT(dst, i) =
|
||||
(p[0] << 24) |
|
||||
(p[1] << 16) |
|
||||
(p[2] << 8) |
|
||||
p[3];
|
||||
p += 4;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mincrypt/p256_ecdsa.h"
|
||||
#include "mincrypt/p256.h"
|
||||
|
||||
int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
|
||||
const p256_int* message,
|
||||
const p256_int* r, const p256_int* s) {
|
||||
p256_int u, v;
|
||||
|
||||
// Check public key.
|
||||
if (!p256_is_valid_point(key_x, key_y)) return 0;
|
||||
|
||||
// Check r and s are != 0 % n.
|
||||
p256_mod(&SECP256r1_n, r, &u);
|
||||
p256_mod(&SECP256r1_n, s, &v);
|
||||
if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
|
||||
|
||||
p256_modinv_vartime(&SECP256r1_n, s, &v);
|
||||
p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n
|
||||
p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n
|
||||
|
||||
p256_points_mul_vartime(&u, &v,
|
||||
key_x, key_y,
|
||||
&u, &v);
|
||||
|
||||
p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n
|
||||
return p256_cmp(r, &u) == 0;
|
||||
}
|
||||
|
@ -0,0 +1,308 @@
|
||||
/* rsa.c
|
||||
**
|
||||
** Copyright 2012, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of Google Inc. nor the names of its contributors may
|
||||
** be used to endorse or promote products derived from this software
|
||||
** without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "mincrypt/rsa.h"
|
||||
#include "mincrypt/sha.h"
|
||||
#include "mincrypt/sha256.h"
|
||||
|
||||
// a[] -= mod
|
||||
static void subM(const RSAPublicKey* key,
|
||||
uint32_t* a) {
|
||||
int64_t A = 0;
|
||||
int i;
|
||||
for (i = 0; i < key->len; ++i) {
|
||||
A += (uint64_t)a[i] - key->n[i];
|
||||
a[i] = (uint32_t)A;
|
||||
A >>= 32;
|
||||
}
|
||||
}
|
||||
|
||||
// return a[] >= mod
|
||||
static int geM(const RSAPublicKey* key,
|
||||
const uint32_t* a) {
|
||||
int i;
|
||||
for (i = key->len; i;) {
|
||||
--i;
|
||||
if (a[i] < key->n[i]) return 0;
|
||||
if (a[i] > key->n[i]) return 1;
|
||||
}
|
||||
return 1; // equal
|
||||
}
|
||||
|
||||
// montgomery c[] += a * b[] / R % mod
|
||||
static void montMulAdd(const RSAPublicKey* key,
|
||||
uint32_t* c,
|
||||
const uint32_t a,
|
||||
const uint32_t* b) {
|
||||
uint64_t A = (uint64_t)a * b[0] + c[0];
|
||||
uint32_t d0 = (uint32_t)A * key->n0inv;
|
||||
uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
A = (A >> 32) + (uint64_t)a * b[i] + c[i];
|
||||
B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
|
||||
c[i - 1] = (uint32_t)B;
|
||||
}
|
||||
|
||||
A = (A >> 32) + (B >> 32);
|
||||
|
||||
c[i - 1] = (uint32_t)A;
|
||||
|
||||
if (A >> 32) {
|
||||
subM(key, c);
|
||||
}
|
||||
}
|
||||
|
||||
// montgomery c[] = a[] * b[] / R % mod
|
||||
static void montMul(const RSAPublicKey* key,
|
||||
uint32_t* c,
|
||||
const uint32_t* a,
|
||||
const uint32_t* b) {
|
||||
int i;
|
||||
for (i = 0; i < key->len; ++i) {
|
||||
c[i] = 0;
|
||||
}
|
||||
for (i = 0; i < key->len; ++i) {
|
||||
montMulAdd(key, c, a[i], b);
|
||||
}
|
||||
}
|
||||
|
||||
// In-place public exponentiation.
|
||||
// Input and output big-endian byte array in inout.
|
||||
static void modpow(const RSAPublicKey* key,
|
||||
uint8_t* inout) {
|
||||
uint32_t a[RSANUMWORDS];
|
||||
uint32_t aR[RSANUMWORDS];
|
||||
uint32_t aaR[RSANUMWORDS];
|
||||
uint32_t* aaa = 0;
|
||||
int i;
|
||||
|
||||
// Convert from big endian byte array to little endian word array.
|
||||
for (i = 0; i < key->len; ++i) {
|
||||
uint32_t tmp =
|
||||
(inout[((key->len - 1 - i) * 4) + 0] << 24) |
|
||||
(inout[((key->len - 1 - i) * 4) + 1] << 16) |
|
||||
(inout[((key->len - 1 - i) * 4) + 2] << 8) |
|
||||
(inout[((key->len - 1 - i) * 4) + 3] << 0);
|
||||
a[i] = tmp;
|
||||
}
|
||||
|
||||
if (key->exponent == 65537) {
|
||||
aaa = aaR; // Re-use location.
|
||||
montMul(key, aR, a, key->rr); // aR = a * RR / R mod M
|
||||
for (i = 0; i < 16; i += 2) {
|
||||
montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M
|
||||
montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M
|
||||
}
|
||||
montMul(key, aaa, aR, a); // aaa = aR * a / R mod M
|
||||
} else if (key->exponent == 3) {
|
||||
aaa = aR; // Re-use location.
|
||||
montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
|
||||
montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
|
||||
montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
|
||||
}
|
||||
|
||||
// Make sure aaa < mod; aaa is at most 1x mod too large.
|
||||
if (geM(key, aaa)) {
|
||||
subM(key, aaa);
|
||||
}
|
||||
|
||||
// Convert to bigendian byte array
|
||||
for (i = key->len - 1; i >= 0; --i) {
|
||||
uint32_t tmp = aaa[i];
|
||||
*inout++ = tmp >> 24;
|
||||
*inout++ = tmp >> 16;
|
||||
*inout++ = tmp >> 8;
|
||||
*inout++ = tmp >> 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
|
||||
// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
|
||||
// other flavor which omits the optional parameter entirely). This code does not
|
||||
// accept signatures without the optional parameter.
|
||||
|
||||
/*
|
||||
static const uint8_t sha_padding[RSANUMBYTES] = {
|
||||
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
|
||||
0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
|
||||
0x05, 0x00, 0x04, 0x14,
|
||||
|
||||
// 20 bytes of hash go here.
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
*/
|
||||
|
||||
// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
|
||||
// At the location of the bytes of the hash all 00 are hashed.
|
||||
static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
|
||||
0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
|
||||
0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
|
||||
0x7c, 0xfb, 0xf1, 0x67
|
||||
};
|
||||
|
||||
/*
|
||||
static const uint8_t sha256_padding[RSANUMBYTES] = {
|
||||
0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
|
||||
0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
|
||||
0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
|
||||
|
||||
// 32 bytes of hash go here.
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
};
|
||||
*/
|
||||
|
||||
// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
|
||||
// At the location of the bytes of the hash all 00 are hashed.
|
||||
static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
|
||||
0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
|
||||
0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
|
||||
0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
|
||||
0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
|
||||
};
|
||||
|
||||
// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
|
||||
// Both e=3 and e=65537 are supported. hash_len may be
|
||||
// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
|
||||
// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other
|
||||
// values are supported.
|
||||
//
|
||||
// Returns 1 on successful verification, 0 on failure.
|
||||
int RSA_verify(const RSAPublicKey *key,
|
||||
const uint8_t *signature,
|
||||
const int len,
|
||||
const uint8_t *hash,
|
||||
const int hash_len) {
|
||||
uint8_t buf[RSANUMBYTES];
|
||||
int i;
|
||||
const uint8_t* padding_hash;
|
||||
|
||||
if (key->len != RSANUMWORDS) {
|
||||
return 0; // Wrong key passed in.
|
||||
}
|
||||
|
||||
if (len != sizeof(buf)) {
|
||||
return 0; // Wrong input length.
|
||||
}
|
||||
|
||||
if (hash_len != SHA_DIGEST_SIZE &&
|
||||
hash_len != SHA256_DIGEST_SIZE) {
|
||||
return 0; // Unsupported hash.
|
||||
}
|
||||
|
||||
if (key->exponent != 3 && key->exponent != 65537) {
|
||||
return 0; // Unsupported exponent.
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i) { // Copy input to local workspace.
|
||||
buf[i] = signature[i];
|
||||
}
|
||||
|
||||
modpow(key, buf); // In-place exponentiation.
|
||||
|
||||
// Xor sha portion, so it all becomes 00 iff equal.
|
||||
for (i = len - hash_len; i < len; ++i) {
|
||||
buf[i] ^= *hash++;
|
||||
}
|
||||
|
||||
// Hash resulting buf, in-place.
|
||||
switch (hash_len) {
|
||||
case SHA_DIGEST_SIZE:
|
||||
padding_hash = kExpectedPadShaRsa2048;
|
||||
SHA_hash(buf, len, buf);
|
||||
break;
|
||||
case SHA256_DIGEST_SIZE:
|
||||
padding_hash = kExpectedPadSha256Rsa2048;
|
||||
SHA256_hash(buf, len, buf);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compare against expected hash value.
|
||||
for (i = 0; i < hash_len; ++i) {
|
||||
if (buf[i] != padding_hash[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1; // All checked out OK.
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/* sha.c
|
||||
**
|
||||
** Copyright 2013, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of Google Inc. nor the names of its contributors may
|
||||
** be used to endorse or promote products derived from this software
|
||||
** without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Optimized for minimal code size.
|
||||
|
||||
#include "mincrypt/sha.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
static void SHA1_Transform(SHA_CTX* ctx) {
|
||||
uint32_t W[80];
|
||||
uint32_t A, B, C, D, E;
|
||||
uint8_t* p = ctx->buf;
|
||||
int t;
|
||||
|
||||
for(t = 0; t < 16; ++t) {
|
||||
uint32_t tmp = *p++ << 24;
|
||||
tmp |= *p++ << 16;
|
||||
tmp |= *p++ << 8;
|
||||
tmp |= *p++;
|
||||
W[t] = tmp;
|
||||
}
|
||||
|
||||
for(; t < 80; t++) {
|
||||
W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
E = ctx->state[4];
|
||||
|
||||
for(t = 0; t < 80; t++) {
|
||||
uint32_t tmp = rol(5,A) + E + W[t];
|
||||
|
||||
if (t < 20)
|
||||
tmp += (D^(B&(C^D))) + 0x5A827999;
|
||||
else if ( t < 40)
|
||||
tmp += (B^C^D) + 0x6ED9EBA1;
|
||||
else if ( t < 60)
|
||||
tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
|
||||
else
|
||||
tmp += (B^C^D) + 0xCA62C1D6;
|
||||
|
||||
E = D;
|
||||
D = C;
|
||||
C = rol(30,B);
|
||||
B = A;
|
||||
A = tmp;
|
||||
}
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
ctx->state[4] += E;
|
||||
}
|
||||
|
||||
static const HASH_VTAB SHA_VTAB = {
|
||||
SHA_init,
|
||||
SHA_update,
|
||||
SHA_final,
|
||||
SHA_hash,
|
||||
SHA_DIGEST_SIZE
|
||||
};
|
||||
|
||||
void SHA_init(SHA_CTX* ctx) {
|
||||
ctx->f = &SHA_VTAB;
|
||||
ctx->state[0] = 0x67452301;
|
||||
ctx->state[1] = 0xEFCDAB89;
|
||||
ctx->state[2] = 0x98BADCFE;
|
||||
ctx->state[3] = 0x10325476;
|
||||
ctx->state[4] = 0xC3D2E1F0;
|
||||
ctx->count = 0;
|
||||
}
|
||||
|
||||
|
||||
void SHA_update(SHA_CTX* ctx, const void* data, int len) {
|
||||
int i = (int) (ctx->count & 63);
|
||||
const uint8_t* p = (const uint8_t*)data;
|
||||
|
||||
ctx->count += len;
|
||||
|
||||
while (len--) {
|
||||
ctx->buf[i++] = *p++;
|
||||
if (i == 64) {
|
||||
SHA1_Transform(ctx);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint8_t* SHA_final(SHA_CTX* ctx) {
|
||||
uint8_t *p = ctx->buf;
|
||||
uint64_t cnt = ctx->count * 8;
|
||||
int i;
|
||||
|
||||
SHA_update(ctx, (uint8_t*)"\x80", 1);
|
||||
while ((ctx->count & 63) != 56) {
|
||||
SHA_update(ctx, (uint8_t*)"\0", 1);
|
||||
}
|
||||
for (i = 0; i < 8; ++i) {
|
||||
uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
|
||||
SHA_update(ctx, &tmp, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
uint32_t tmp = ctx->state[i];
|
||||
*p++ = tmp >> 24;
|
||||
*p++ = tmp >> 16;
|
||||
*p++ = tmp >> 8;
|
||||
*p++ = tmp >> 0;
|
||||
}
|
||||
|
||||
return ctx->buf;
|
||||
}
|
||||
|
||||
/* Convenience function */
|
||||
const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
|
||||
SHA_CTX ctx;
|
||||
SHA_init(&ctx);
|
||||
SHA_update(&ctx, data, len);
|
||||
memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
|
||||
return digest;
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
/* sha256.c
|
||||
**
|
||||
** Copyright 2013, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of Google Inc. nor the names of its contributors may
|
||||
** be used to endorse or promote products derived from this software
|
||||
** without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Optimized for minimal code size.
|
||||
|
||||
#include "mincrypt/sha256.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
|
||||
#define shr(value, bits) ((value) >> (bits))
|
||||
|
||||
static const uint32_t K[64] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
|
||||
|
||||
static void SHA256_Transform(SHA256_CTX* ctx) {
|
||||
uint32_t W[64];
|
||||
uint32_t A, B, C, D, E, F, G, H;
|
||||
uint8_t* p = ctx->buf;
|
||||
int t;
|
||||
|
||||
for(t = 0; t < 16; ++t) {
|
||||
uint32_t tmp = *p++ << 24;
|
||||
tmp |= *p++ << 16;
|
||||
tmp |= *p++ << 8;
|
||||
tmp |= *p++;
|
||||
W[t] = tmp;
|
||||
}
|
||||
|
||||
for(; t < 64; t++) {
|
||||
uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
|
||||
uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
|
||||
W[t] = W[t-16] + s0 + W[t-7] + s1;
|
||||
}
|
||||
|
||||
A = ctx->state[0];
|
||||
B = ctx->state[1];
|
||||
C = ctx->state[2];
|
||||
D = ctx->state[3];
|
||||
E = ctx->state[4];
|
||||
F = ctx->state[5];
|
||||
G = ctx->state[6];
|
||||
H = ctx->state[7];
|
||||
|
||||
for(t = 0; t < 64; t++) {
|
||||
uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
|
||||
uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
|
||||
uint32_t t2 = s0 + maj;
|
||||
uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
|
||||
uint32_t ch = (E & F) ^ ((~E) & G);
|
||||
uint32_t t1 = H + s1 + ch + K[t] + W[t];
|
||||
|
||||
H = G;
|
||||
G = F;
|
||||
F = E;
|
||||
E = D + t1;
|
||||
D = C;
|
||||
C = B;
|
||||
B = A;
|
||||
A = t1 + t2;
|
||||
}
|
||||
|
||||
ctx->state[0] += A;
|
||||
ctx->state[1] += B;
|
||||
ctx->state[2] += C;
|
||||
ctx->state[3] += D;
|
||||
ctx->state[4] += E;
|
||||
ctx->state[5] += F;
|
||||
ctx->state[6] += G;
|
||||
ctx->state[7] += H;
|
||||
}
|
||||
|
||||
static const HASH_VTAB SHA256_VTAB = {
|
||||
SHA256_init,
|
||||
SHA256_update,
|
||||
SHA256_final,
|
||||
SHA256_hash,
|
||||
SHA256_DIGEST_SIZE
|
||||
};
|
||||
|
||||
void SHA256_init(SHA256_CTX* ctx) {
|
||||
ctx->f = &SHA256_VTAB;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
ctx->count = 0;
|
||||
}
|
||||
|
||||
|
||||
void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
|
||||
int i = (int) (ctx->count & 63);
|
||||
const uint8_t* p = (const uint8_t*)data;
|
||||
|
||||
ctx->count += len;
|
||||
|
||||
while (len--) {
|
||||
ctx->buf[i++] = *p++;
|
||||
if (i == 64) {
|
||||
SHA256_Transform(ctx);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint8_t* SHA256_final(SHA256_CTX* ctx) {
|
||||
uint8_t *p = ctx->buf;
|
||||
uint64_t cnt = ctx->count * 8;
|
||||
int i;
|
||||
|
||||
SHA256_update(ctx, (uint8_t*)"\x80", 1);
|
||||
while ((ctx->count & 63) != 56) {
|
||||
SHA256_update(ctx, (uint8_t*)"\0", 1);
|
||||
}
|
||||
for (i = 0; i < 8; ++i) {
|
||||
uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
|
||||
SHA256_update(ctx, &tmp, 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
uint32_t tmp = ctx->state[i];
|
||||
*p++ = tmp >> 24;
|
||||
*p++ = tmp >> 16;
|
||||
*p++ = tmp >> 8;
|
||||
*p++ = tmp >> 0;
|
||||
}
|
||||
|
||||
return ctx->buf;
|
||||
}
|
||||
|
||||
/* Convenience function */
|
||||
const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
|
||||
SHA256_CTX ctx;
|
||||
SHA256_init(&ctx);
|
||||
SHA256_update(&ctx, data, len);
|
||||
memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
|
||||
return digest;
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
|
||||
|
||||
#include "mincrypt/p256.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Returns 0 if input sig is not a valid ASN.1 sequence
|
||||
int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2007 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
struct HASH_CTX; // forward decl
|
||||
|
||||
typedef struct HASH_VTAB {
|
||||
void (* const init)(struct HASH_CTX*);
|
||||
void (* const update)(struct HASH_CTX*, const void*, int);
|
||||
const uint8_t* (* const final)(struct HASH_CTX*);
|
||||
const uint8_t* (* const hash)(const void*, int, uint8_t*);
|
||||
int size;
|
||||
} HASH_VTAB;
|
||||
|
||||
typedef struct HASH_CTX {
|
||||
const HASH_VTAB * f;
|
||||
uint64_t count;
|
||||
uint8_t buf[64];
|
||||
uint32_t state[8]; // upto SHA2
|
||||
} HASH_CTX;
|
||||
|
||||
#define HASH_init(ctx) (ctx)->f->init(ctx)
|
||||
#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
|
||||
#define HASH_final(ctx) (ctx)->f->final(ctx)
|
||||
#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
|
||||
#define HASH_size(ctx) (ctx)->f->size
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
|
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
|
||||
|
||||
// Collection of routines manipulating 256 bit unsigned integers.
|
||||
// Just enough to implement ecdsa-p256 and related algorithms.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define P256_BITSPERDIGIT 32
|
||||
#define P256_NDIGITS 8
|
||||
#define P256_NBYTES 32
|
||||
|
||||
typedef int p256_err;
|
||||
typedef uint32_t p256_digit;
|
||||
typedef int32_t p256_sdigit;
|
||||
typedef uint64_t p256_ddigit;
|
||||
typedef int64_t p256_sddigit;
|
||||
|
||||
// Defining p256_int as struct to leverage struct assigment.
|
||||
typedef struct {
|
||||
p256_digit a[P256_NDIGITS];
|
||||
} p256_int;
|
||||
|
||||
extern const p256_int SECP256r1_n; // Curve order
|
||||
extern const p256_int SECP256r1_p; // Curve prime
|
||||
extern const p256_int SECP256r1_b; // Curve param
|
||||
|
||||
// Initialize a p256_int to zero.
|
||||
void p256_init(p256_int* a);
|
||||
|
||||
// Clear a p256_int to zero.
|
||||
void p256_clear(p256_int* a);
|
||||
|
||||
// Return bit. Index 0 is least significant.
|
||||
int p256_get_bit(const p256_int* a, int index);
|
||||
|
||||
// b := a % MOD
|
||||
void p256_mod(
|
||||
const p256_int* MOD,
|
||||
const p256_int* a,
|
||||
p256_int* b);
|
||||
|
||||
// c := a * (top_b | b) % MOD
|
||||
void p256_modmul(
|
||||
const p256_int* MOD,
|
||||
const p256_int* a,
|
||||
const p256_digit top_b,
|
||||
const p256_int* b,
|
||||
p256_int* c);
|
||||
|
||||
// b := 1 / a % MOD
|
||||
// MOD best be SECP256r1_n
|
||||
void p256_modinv(
|
||||
const p256_int* MOD,
|
||||
const p256_int* a,
|
||||
p256_int* b);
|
||||
|
||||
// b := 1 / a % MOD
|
||||
// MOD best be SECP256r1_n
|
||||
// Faster than p256_modinv()
|
||||
void p256_modinv_vartime(
|
||||
const p256_int* MOD,
|
||||
const p256_int* a,
|
||||
p256_int* b);
|
||||
|
||||
// b := a << (n % P256_BITSPERDIGIT)
|
||||
// Returns the bits shifted out of most significant digit.
|
||||
p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
|
||||
|
||||
// b := a >> (n % P256_BITSPERDIGIT)
|
||||
void p256_shr(const p256_int* a, int n, p256_int* b);
|
||||
|
||||
int p256_is_zero(const p256_int* a);
|
||||
int p256_is_odd(const p256_int* a);
|
||||
int p256_is_even(const p256_int* a);
|
||||
|
||||
// Returns -1, 0 or 1.
|
||||
int p256_cmp(const p256_int* a, const p256_int *b);
|
||||
|
||||
// c: = a - b
|
||||
// Returns -1 on borrow.
|
||||
int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
|
||||
|
||||
// c := a + b
|
||||
// Returns 1 on carry.
|
||||
int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
|
||||
|
||||
// c := a + (single digit)b
|
||||
// Returns carry 1 on carry.
|
||||
int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
|
||||
|
||||
// ec routines.
|
||||
|
||||
// {out_x,out_y} := nG
|
||||
void p256_base_point_mul(const p256_int *n,
|
||||
p256_int *out_x,
|
||||
p256_int *out_y);
|
||||
|
||||
// {out_x,out_y} := n{in_x,in_y}
|
||||
void p256_point_mul(const p256_int *n,
|
||||
const p256_int *in_x,
|
||||
const p256_int *in_y,
|
||||
p256_int *out_x,
|
||||
p256_int *out_y);
|
||||
|
||||
// {out_x,out_y} := n1G + n2{in_x,in_y}
|
||||
void p256_points_mul_vartime(
|
||||
const p256_int *n1, const p256_int *n2,
|
||||
const p256_int *in_x, const p256_int *in_y,
|
||||
p256_int *out_x, p256_int *out_y);
|
||||
|
||||
// Return whether point {x,y} is on curve.
|
||||
int p256_is_valid_point(const p256_int* x, const p256_int* y);
|
||||
|
||||
// Outputs big-endian binary form. No leading zero skips.
|
||||
void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
|
||||
|
||||
// Reads from big-endian binary form,
|
||||
// thus pre-pad with leading zeros if short.
|
||||
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
|
||||
|
||||
#define P256_DIGITS(x) ((x)->a)
|
||||
#define P256_DIGIT(x,y) ((x)->a[y])
|
||||
|
||||
#define P256_ZERO {{0}}
|
||||
#define P256_ONE {{1}}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2013 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
|
||||
|
||||
// Using current directory as relative include path here since
|
||||
// this code typically gets lifted into a variety of build systems
|
||||
// and directory structures.
|
||||
#include "p256.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Returns 0 if {r,s} is not a signature on message for
|
||||
// public key {key_x,key_y}.
|
||||
//
|
||||
// Note: message is a p256_int.
|
||||
// Convert from a binary string using p256_from_bin().
|
||||
int p256_ecdsa_verify(const p256_int* key_x,
|
||||
const p256_int* key_y,
|
||||
const p256_int* message,
|
||||
const p256_int* r, const p256_int* s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
|
@ -0,0 +1,58 @@
|
||||
/* rsa.h
|
||||
**
|
||||
** Copyright 2008, The Android Open Source Project
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** * Neither the name of Google Inc. nor the names of its contributors may
|
||||
** be used to endorse or promote products derived from this software
|
||||
** without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RSANUMBYTES 256 /* 2048 bit key length */
|
||||
#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
|
||||
|
||||
typedef struct RSAPublicKey {
|
||||
int len; /* Length of n[] in number of uint32_t */
|
||||
uint32_t n0inv; /* -1 / n[0] mod 2^32 */
|
||||
uint32_t n[RSANUMWORDS]; /* modulus as little endian array */
|
||||
uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
|
||||
int exponent; /* 3 or 65537 */
|
||||
} RSAPublicKey;
|
||||
|
||||
int RSA_verify(const RSAPublicKey *key,
|
||||
const uint8_t* signature,
|
||||
const int len,
|
||||
const uint8_t* hash,
|
||||
const int hash_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2005 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hash-internal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef HASH_CTX SHA_CTX;
|
||||
|
||||
void SHA_init(SHA_CTX* ctx);
|
||||
void SHA_update(SHA_CTX* ctx, const void* data, int len);
|
||||
const uint8_t* SHA_final(SHA_CTX* ctx);
|
||||
|
||||
// Convenience method. Returns digest address.
|
||||
// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
|
||||
const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
|
||||
|
||||
#define SHA_DIGEST_SIZE 20
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2011 The Android Open Source Project
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
|
||||
#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hash-internal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
typedef HASH_CTX SHA256_CTX;
|
||||
|
||||
void SHA256_init(SHA256_CTX* ctx);
|
||||
void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
|
||||
const uint8_t* SHA256_final(SHA256_CTX* ctx);
|
||||
|
||||
// Convenience method. Returns digest address.
|
||||
const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
|
@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2008 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.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := dumpkey
|
||||
LOCAL_SRC_FILES := DumpPublicKey.java
|
||||
LOCAL_JAR_MANIFEST := DumpPublicKey.mf
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (C) 2008 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.dumpkey;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.KeyStore;
|
||||
import java.security.Key;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Security;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.ECPoint;
|
||||
|
||||
/**
|
||||
* Command line tool to extract RSA public keys from X.509 certificates
|
||||
* and output source code with data initializers for the keys.
|
||||
* @hide
|
||||
*/
|
||||
class DumpPublicKey {
|
||||
/**
|
||||
* @param key to perform sanity checks on
|
||||
* @return version number of key. Supported versions are:
|
||||
* 1: 2048-bit RSA key with e=3 and SHA-1 hash
|
||||
* 2: 2048-bit RSA key with e=65537 and SHA-1 hash
|
||||
* 3: 2048-bit RSA key with e=3 and SHA-256 hash
|
||||
* 4: 2048-bit RSA key with e=65537 and SHA-256 hash
|
||||
* @throws Exception if the key has the wrong size or public exponent
|
||||
*/
|
||||
static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
|
||||
BigInteger pubexp = key.getPublicExponent();
|
||||
BigInteger modulus = key.getModulus();
|
||||
int version;
|
||||
|
||||
if (pubexp.equals(BigInteger.valueOf(3))) {
|
||||
version = useSHA256 ? 3 : 1;
|
||||
} else if (pubexp.equals(BigInteger.valueOf(65537))) {
|
||||
version = useSHA256 ? 4 : 2;
|
||||
} else {
|
||||
throw new Exception("Public exponent should be 3 or 65537 but is " +
|
||||
pubexp.toString(10) + ".");
|
||||
}
|
||||
|
||||
if (modulus.bitLength() != 2048) {
|
||||
throw new Exception("Modulus should be 2048 bits long but is " +
|
||||
modulus.bitLength() + " bits.");
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key to perform sanity checks on
|
||||
* @return version number of key. Supported versions are:
|
||||
* 5: 256-bit EC key with curve NIST P-256
|
||||
* @throws Exception if the key has the wrong size or public exponent
|
||||
*/
|
||||
static int checkEC(ECPublicKey key) throws Exception {
|
||||
if (key.getParams().getCurve().getField().getFieldSize() != 256) {
|
||||
throw new Exception("Curve must be NIST P-256");
|
||||
}
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform sanity check on public key.
|
||||
*/
|
||||
static int check(PublicKey key, boolean useSHA256) throws Exception {
|
||||
if (key instanceof RSAPublicKey) {
|
||||
return checkRSA((RSAPublicKey) key, useSHA256);
|
||||
} else if (key instanceof ECPublicKey) {
|
||||
if (!useSHA256) {
|
||||
throw new Exception("Must use SHA-256 with EC keys!");
|
||||
}
|
||||
return checkEC((ECPublicKey) key);
|
||||
} else {
|
||||
throw new Exception("Unsupported key class: " + key.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key to output
|
||||
* @return a String representing this public key. If the key is a
|
||||
* version 1 key, the string will be a C initializer; this is
|
||||
* not true for newer key versions.
|
||||
*/
|
||||
static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
|
||||
int version = check(key, useSHA256);
|
||||
|
||||
BigInteger N = key.getModulus();
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
|
||||
|
||||
if (version > 1) {
|
||||
result.append("v");
|
||||
result.append(Integer.toString(version));
|
||||
result.append(" ");
|
||||
}
|
||||
|
||||
result.append("{");
|
||||
result.append(nwords);
|
||||
|
||||
BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32
|
||||
BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32
|
||||
|
||||
result.append(",0x");
|
||||
result.append(N0inv.toString(16));
|
||||
|
||||
BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
|
||||
BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N
|
||||
|
||||
// Write out modulus as little endian array of integers.
|
||||
result.append(",{");
|
||||
for (int i = 0; i < nwords; ++i) {
|
||||
long n = N.mod(B).longValue();
|
||||
result.append(n);
|
||||
|
||||
if (i != nwords - 1) {
|
||||
result.append(",");
|
||||
}
|
||||
|
||||
N = N.divide(B);
|
||||
}
|
||||
result.append("}");
|
||||
|
||||
// Write R^2 as little endian array of integers.
|
||||
result.append(",{");
|
||||
for (int i = 0; i < nwords; ++i) {
|
||||
long rr = RR.mod(B).longValue();
|
||||
result.append(rr);
|
||||
|
||||
if (i != nwords - 1) {
|
||||
result.append(",");
|
||||
}
|
||||
|
||||
RR = RR.divide(B);
|
||||
}
|
||||
result.append("}");
|
||||
|
||||
result.append("}");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key to output
|
||||
* @return a String representing this public key. If the key is a
|
||||
* version 1 key, the string will be a C initializer; this is
|
||||
* not true for newer key versions.
|
||||
*/
|
||||
static String printEC(ECPublicKey key) throws Exception {
|
||||
int version = checkEC(key);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append("v");
|
||||
result.append(Integer.toString(version));
|
||||
result.append(" ");
|
||||
|
||||
BigInteger X = key.getW().getAffineX();
|
||||
BigInteger Y = key.getW().getAffineY();
|
||||
int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate
|
||||
|
||||
result.append("{");
|
||||
result.append(nbytes);
|
||||
|
||||
BigInteger B = BigInteger.valueOf(0x100L); // 2^8
|
||||
|
||||
// Write out Y coordinate as array of characters.
|
||||
result.append(",{");
|
||||
for (int i = 0; i < nbytes; ++i) {
|
||||
long n = X.mod(B).longValue();
|
||||
result.append(n);
|
||||
|
||||
if (i != nbytes - 1) {
|
||||
result.append(",");
|
||||
}
|
||||
|
||||
X = X.divide(B);
|
||||
}
|
||||
result.append("}");
|
||||
|
||||
// Write out Y coordinate as array of characters.
|
||||
result.append(",{");
|
||||
for (int i = 0; i < nbytes; ++i) {
|
||||
long n = Y.mod(B).longValue();
|
||||
result.append(n);
|
||||
|
||||
if (i != nbytes - 1) {
|
||||
result.append(",");
|
||||
}
|
||||
|
||||
Y = Y.divide(B);
|
||||
}
|
||||
result.append("}");
|
||||
|
||||
result.append("}");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
static String print(PublicKey key, boolean useSHA256) throws Exception {
|
||||
if (key instanceof RSAPublicKey) {
|
||||
return printRSA((RSAPublicKey) key, useSHA256);
|
||||
} else if (key instanceof ECPublicKey) {
|
||||
return printEC((ECPublicKey) key);
|
||||
} else {
|
||||
throw new Exception("Unsupported key class: " + key.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length < 1) {
|
||||
System.err.println("Usage: DumpPublicKey certfile ... > source.c");
|
||||
System.exit(1);
|
||||
}
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
try {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
FileInputStream input = new FileInputStream(args[i]);
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
|
||||
|
||||
boolean useSHA256 = false;
|
||||
String sigAlg = cert.getSigAlgName();
|
||||
if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
|
||||
// SignApk has historically accepted "MD5withRSA"
|
||||
// certificates, but treated them as "SHA1withRSA"
|
||||
// anyway. Continue to do so for backwards
|
||||
// compatibility.
|
||||
useSHA256 = false;
|
||||
} else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
|
||||
useSHA256 = true;
|
||||
} else {
|
||||
System.err.println(args[i] + ": unsupported signature algorithm \"" +
|
||||
sigAlg + "\"");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
PublicKey key = cert.getPublicKey();
|
||||
check(key, useSHA256);
|
||||
System.out.print(print(key, useSHA256));
|
||||
System.out.println(i < args.length - 1 ? "," : "");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
Main-Class: com.android.dumpkey.DumpPublicKey
|
@ -0,0 +1,292 @@
|
||||
/* tools/mkbootimg/mkbootimg.c
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "mincrypt/sha.h"
|
||||
#include "bootimg.h"
|
||||
|
||||
static void *load_file(const char *fn, unsigned *_sz)
|
||||
{
|
||||
char *data;
|
||||
int sz;
|
||||
int fd;
|
||||
|
||||
data = 0;
|
||||
fd = open(fn, O_RDONLY);
|
||||
if(fd < 0) return 0;
|
||||
|
||||
sz = lseek(fd, 0, SEEK_END);
|
||||
if(sz < 0) goto oops;
|
||||
|
||||
if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
|
||||
|
||||
data = (char*) malloc(sz);
|
||||
if(data == 0) goto oops;
|
||||
|
||||
if(read(fd, data, sz) != sz) goto oops;
|
||||
close(fd);
|
||||
|
||||
if(_sz) *_sz = sz;
|
||||
return data;
|
||||
|
||||
oops:
|
||||
close(fd);
|
||||
if(data != 0) free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usage(void)
|
||||
{
|
||||
fprintf(stderr,"usage: mkbootimg\n"
|
||||
" --kernel <filename>\n"
|
||||
" [ --ramdisk <filename> ]\n"
|
||||
" [ --second <2ndbootloader-filename> ]\n"
|
||||
" [ --cmdline <kernel-commandline> ]\n"
|
||||
" [ --board <boardname> ]\n"
|
||||
" [ --base <address> ]\n"
|
||||
" [ --pagesize <pagesize> ]\n"
|
||||
" [ --id ]\n"
|
||||
" -o|--output <filename>\n"
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned char padding[16384] = { 0, };
|
||||
|
||||
static void print_id(const uint8_t *id, size_t id_len) {
|
||||
printf("0x");
|
||||
for (unsigned i = 0; i < id_len; i++) {
|
||||
printf("%02x", id[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int write_padding(int fd, unsigned pagesize, unsigned itemsize)
|
||||
{
|
||||
unsigned pagemask = pagesize - 1;
|
||||
ssize_t count;
|
||||
|
||||
if((itemsize & pagemask) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
count = pagesize - (itemsize & pagemask);
|
||||
|
||||
if(write(fd, padding, count) != count) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
boot_img_hdr hdr;
|
||||
|
||||
char *kernel_fn = NULL;
|
||||
void *kernel_data = NULL;
|
||||
char *ramdisk_fn = NULL;
|
||||
void *ramdisk_data = NULL;
|
||||
char *second_fn = NULL;
|
||||
void *second_data = NULL;
|
||||
char *cmdline = "";
|
||||
char *bootimg = NULL;
|
||||
char *board = "";
|
||||
uint32_t pagesize = 2048;
|
||||
int fd;
|
||||
SHA_CTX ctx;
|
||||
const uint8_t* sha;
|
||||
uint32_t base = 0x10000000U;
|
||||
uint32_t kernel_offset = 0x00008000U;
|
||||
uint32_t ramdisk_offset = 0x01000000U;
|
||||
uint32_t second_offset = 0x00f00000U;
|
||||
uint32_t tags_offset = 0x00000100U;
|
||||
size_t cmdlen;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
|
||||
bool get_id = false;
|
||||
while(argc > 0){
|
||||
char *arg = argv[0];
|
||||
if (!strcmp(arg, "--id")) {
|
||||
get_id = true;
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
} else if(argc >= 2) {
|
||||
char *val = argv[1];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
|
||||
bootimg = val;
|
||||
} else if(!strcmp(arg, "--kernel")) {
|
||||
kernel_fn = val;
|
||||
} else if(!strcmp(arg, "--ramdisk")) {
|
||||
ramdisk_fn = val;
|
||||
} else if(!strcmp(arg, "--second")) {
|
||||
second_fn = val;
|
||||
} else if(!strcmp(arg, "--cmdline")) {
|
||||
cmdline = val;
|
||||
} else if(!strcmp(arg, "--base")) {
|
||||
base = strtoul(val, 0, 16);
|
||||
} else if(!strcmp(arg, "--kernel_offset")) {
|
||||
kernel_offset = strtoul(val, 0, 16);
|
||||
} else if(!strcmp(arg, "--ramdisk_offset")) {
|
||||
ramdisk_offset = strtoul(val, 0, 16);
|
||||
} else if(!strcmp(arg, "--second_offset")) {
|
||||
second_offset = strtoul(val, 0, 16);
|
||||
} else if(!strcmp(arg, "--tags_offset")) {
|
||||
tags_offset = strtoul(val, 0, 16);
|
||||
} else if(!strcmp(arg, "--board")) {
|
||||
board = val;
|
||||
} else if(!strcmp(arg,"--pagesize")) {
|
||||
pagesize = strtoul(val, 0, 10);
|
||||
if ((pagesize != 2048) && (pagesize != 4096)
|
||||
&& (pagesize != 8192) && (pagesize != 16384)) {
|
||||
fprintf(stderr,"error: unsupported page size %d\n", pagesize);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return usage();
|
||||
}
|
||||
} else {
|
||||
return usage();
|
||||
}
|
||||
}
|
||||
hdr.page_size = pagesize;
|
||||
|
||||
hdr.kernel_addr = base + kernel_offset;
|
||||
hdr.ramdisk_addr = base + ramdisk_offset;
|
||||
hdr.second_addr = base + second_offset;
|
||||
hdr.tags_addr = base + tags_offset;
|
||||
|
||||
if(bootimg == 0) {
|
||||
fprintf(stderr,"error: no output filename specified\n");
|
||||
return usage();
|
||||
}
|
||||
|
||||
if(kernel_fn == 0) {
|
||||
fprintf(stderr,"error: no kernel image specified\n");
|
||||
return usage();
|
||||
}
|
||||
|
||||
if(strlen(board) >= BOOT_NAME_SIZE) {
|
||||
fprintf(stderr,"error: board name too large\n");
|
||||
return usage();
|
||||
}
|
||||
|
||||
strcpy((char *) hdr.name, board);
|
||||
|
||||
memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
|
||||
|
||||
cmdlen = strlen(cmdline);
|
||||
if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) {
|
||||
fprintf(stderr,"error: kernel commandline too large\n");
|
||||
return 1;
|
||||
}
|
||||
/* Even if we need to use the supplemental field, ensure we
|
||||
* are still NULL-terminated */
|
||||
strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1);
|
||||
hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0';
|
||||
if (cmdlen >= (BOOT_ARGS_SIZE - 1)) {
|
||||
cmdline += (BOOT_ARGS_SIZE - 1);
|
||||
strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE);
|
||||
}
|
||||
|
||||
kernel_data = load_file(kernel_fn, &hdr.kernel_size);
|
||||
if(kernel_data == 0) {
|
||||
fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(ramdisk_fn == 0) {
|
||||
ramdisk_data = 0;
|
||||
hdr.ramdisk_size = 0;
|
||||
} else {
|
||||
ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
|
||||
if(ramdisk_data == 0) {
|
||||
fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(second_fn) {
|
||||
second_data = load_file(second_fn, &hdr.second_size);
|
||||
if(second_data == 0) {
|
||||
fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* put a hash of the contents in the header so boot images can be
|
||||
* differentiated based on their first 2k.
|
||||
*/
|
||||
SHA_init(&ctx);
|
||||
SHA_update(&ctx, kernel_data, hdr.kernel_size);
|
||||
SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
|
||||
SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
|
||||
SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
|
||||
SHA_update(&ctx, second_data, hdr.second_size);
|
||||
SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
|
||||
sha = SHA_final(&ctx);
|
||||
memcpy(hdr.id, sha,
|
||||
SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
|
||||
|
||||
fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
|
||||
if(fd < 0) {
|
||||
fprintf(stderr,"error: could not create '%s'\n", bootimg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
|
||||
if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
|
||||
|
||||
if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail;
|
||||
if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
|
||||
|
||||
if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail;
|
||||
if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
|
||||
|
||||
if(second_data) {
|
||||
if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail;
|
||||
if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
|
||||
}
|
||||
|
||||
if (get_id) {
|
||||
print_id((uint8_t *) hdr.id, sizeof(hdr.id));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
unlink(bootimg);
|
||||
close(fd);
|
||||
fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/* tools/mkbootimg/bootimg.h
|
||||
**
|
||||
** Copyright 2007, 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.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef _BOOT_IMAGE_H_
|
||||
#define _BOOT_IMAGE_H_
|
||||
|
||||
typedef struct boot_img_hdr boot_img_hdr;
|
||||
|
||||
#define BOOT_MAGIC "ANDROID!"
|
||||
#define BOOT_MAGIC_SIZE 8
|
||||
#define BOOT_NAME_SIZE 16
|
||||
#define BOOT_ARGS_SIZE 512
|
||||
#define BOOT_EXTRA_ARGS_SIZE 1024
|
||||
|
||||
struct boot_img_hdr
|
||||
{
|
||||
uint8_t magic[BOOT_MAGIC_SIZE];
|
||||
|
||||
uint32_t kernel_size; /* size in bytes */
|
||||
uint32_t kernel_addr; /* physical load addr */
|
||||
|
||||
uint32_t ramdisk_size; /* size in bytes */
|
||||
uint32_t ramdisk_addr; /* physical load addr */
|
||||
|
||||
uint32_t second_size; /* size in bytes */
|
||||
uint32_t second_addr; /* physical load addr */
|
||||
|
||||
uint32_t tags_addr; /* physical addr for kernel tags */
|
||||
uint32_t page_size; /* flash page size we assume */
|
||||
uint32_t unused[2]; /* future expansion: should be 0 */
|
||||
|
||||
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
|
||||
|
||||
uint8_t cmdline[BOOT_ARGS_SIZE];
|
||||
|
||||
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
|
||||
|
||||
/* Supplemental command line data; kept here to maintain
|
||||
* binary compatibility with older versions of mkbootimg */
|
||||
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
** +-----------------+
|
||||
** | boot header | 1 page
|
||||
** +-----------------+
|
||||
** | kernel | n pages
|
||||
** +-----------------+
|
||||
** | ramdisk | m pages
|
||||
** +-----------------+
|
||||
** | second stage | o pages
|
||||
** +-----------------+
|
||||
**
|
||||
** n = (kernel_size + page_size - 1) / page_size
|
||||
** m = (ramdisk_size + page_size - 1) / page_size
|
||||
** o = (second_size + page_size - 1) / page_size
|
||||
**
|
||||
** 0. all entities are page_size aligned in flash
|
||||
** 1. kernel and ramdisk are required (size != 0)
|
||||
** 2. second is optional (second_size == 0 -> no second)
|
||||
** 3. load each element (kernel, ramdisk, second) at
|
||||
** the specified physical address (kernel_addr, etc)
|
||||
** 4. prepare tags at tag_addr. kernel_args[] is
|
||||
** appended to the kernel commandline in the tags.
|
||||
** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
|
||||
** 6. if second_size != 0: jump to second_addr
|
||||
** else: jump to kernel_addr
|
||||
*/
|
||||
|
||||
#if 0
|
||||
typedef struct ptentry ptentry;
|
||||
|
||||
struct ptentry {
|
||||
char name[16]; /* asciiz partition name */
|
||||
unsigned start; /* starting block number */
|
||||
unsigned length; /* length in blocks */
|
||||
unsigned flags; /* set to zero */
|
||||
};
|
||||
|
||||
/* MSM Partition Table ATAG
|
||||
**
|
||||
** length: 2 + 7 * n
|
||||
** atag: 0x4d534d70
|
||||
** <ptentry> x n
|
||||
*/
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue