├── settings.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── BraintreeAndroidEncryption ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ ├── braintree │ │ │ └── org │ │ │ │ └── bouncycastle │ │ │ │ ├── asn1 │ │ │ │ ├── ASN1String.java │ │ │ │ ├── DEREncodable.java │ │ │ │ ├── DERString.java │ │ │ │ ├── InMemoryRepresentable.java │ │ │ │ ├── ASN1OctetStringParser.java │ │ │ │ ├── ASN1SequenceParser.java │ │ │ │ ├── ASN1SetParser.java │ │ │ │ ├── BERApplicationSpecific.java │ │ │ │ ├── ASN1ApplicationSpecificParser.java │ │ │ │ ├── ASN1Boolean.java │ │ │ │ ├── ASN1TaggedObjectParser.java │ │ │ │ ├── ASN1UTCTime.java │ │ │ │ ├── ASN1Integer.java │ │ │ │ ├── ASN1Enumerated.java │ │ │ │ ├── ASN1GeneralizedTime.java │ │ │ │ ├── DERObject.java │ │ │ │ ├── DERNull.java │ │ │ │ ├── ASN1Choice.java │ │ │ │ ├── ASN1ParsingException.java │ │ │ │ ├── ASN1Exception.java │ │ │ │ ├── ASN1EncodableVector.java │ │ │ │ ├── BERFactory.java │ │ │ │ ├── DERFactory.java │ │ │ │ ├── ASN1ObjectIdentifier.java │ │ │ │ ├── ASN1Null.java │ │ │ │ ├── LimitedInputStream.java │ │ │ │ ├── DEREncodableVector.java │ │ │ │ ├── DEROctetString.java │ │ │ │ ├── BEROutputStream.java │ │ │ │ ├── ASN1OutputStream.java │ │ │ │ ├── BERSetParser.java │ │ │ │ ├── DERSetParser.java │ │ │ │ ├── DERSequenceParser.java │ │ │ │ ├── BERSequenceParser.java │ │ │ │ ├── DEROctetStringParser.java │ │ │ │ ├── LazyDERConstructionEnumeration.java │ │ │ │ ├── BERApplicationSpecificParser.java │ │ │ │ ├── BEROctetStringParser.java │ │ │ │ ├── OIDTokenizer.java │ │ │ │ ├── ASN1Object.java │ │ │ │ ├── DERExternalParser.java │ │ │ │ ├── BERSequence.java │ │ │ │ ├── BERSet.java │ │ │ │ ├── LazyDERSequence.java │ │ │ │ ├── DERTags.java │ │ │ │ ├── DERUnknownTag.java │ │ │ │ ├── BERTaggedObjectParser.java │ │ │ │ ├── DERSequence.java │ │ │ │ ├── DERTaggedObject.java │ │ │ │ ├── DERGeneralString.java │ │ │ │ ├── DERSet.java │ │ │ │ ├── IndefiniteLengthInputStream.java │ │ │ │ ├── DEREnumerated.java │ │ │ │ ├── DefiniteLengthInputStream.java │ │ │ │ ├── ASN1Encodable.java │ │ │ │ ├── x509 │ │ │ │ │ └── RSAPublicKeyStructure.java │ │ │ │ ├── ConstructedOctetStream.java │ │ │ │ ├── DERUTF8String.java │ │ │ │ ├── DERBoolean.java │ │ │ │ ├── DERInteger.java │ │ │ │ ├── DERT61String.java │ │ │ │ ├── DERBMPString.java │ │ │ │ ├── DERVisibleString.java │ │ │ │ ├── DEROutputStream.java │ │ │ │ ├── BERTaggedObject.java │ │ │ │ ├── DERUniversalString.java │ │ │ │ ├── ASN1OctetString.java │ │ │ │ ├── BERConstructedOctetString.java │ │ │ │ ├── DERIA5String.java │ │ │ │ ├── DERNumericString.java │ │ │ │ ├── DERPrintableString.java │ │ │ │ ├── ASN1TaggedObject.java │ │ │ │ ├── DERApplicationSpecific.java │ │ │ │ ├── ASN1Sequence.java │ │ │ │ └── DERUTCTime.java │ │ │ │ ├── util │ │ │ │ ├── io │ │ │ │ │ ├── StreamOverflowException.java │ │ │ │ │ └── Streams.java │ │ │ │ ├── encoders │ │ │ │ │ ├── Encoder.java │ │ │ │ │ ├── Base64.java │ │ │ │ │ ├── Hex.java │ │ │ │ │ └── HexEncoder.java │ │ │ │ └── Arrays.java │ │ │ │ └── LICENSE.java │ │ │ └── braintreegateway │ │ │ └── encryption │ │ │ ├── BraintreeEncryptionException.java │ │ │ ├── Random.java │ │ │ ├── Braintree.java │ │ │ ├── Aes.java │ │ │ └── Rsa.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── braintreegateway │ │ └── encryption │ │ ├── util │ │ ├── RsaDecrypter.java │ │ └── AesDecrypter.java │ │ └── test │ │ ├── AesTest.java │ │ ├── RsaTest.java │ │ └── BraintreeTest.java └── build.gradle ├── .github └── ISSUE_TEMPLATE.md ├── README.md ├── LICENSE ├── Rakefile ├── gradlew.bat └── gradlew /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':BraintreeAndroidEncryption' 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | local.properties 5 | gradle.properties 6 | .DS_Store 7 | *.iml 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braintree/braintree_android_encryption/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # :warning: DEPRECATED :warning: 2 | This integration method is deprecated. Please upgrade to the latest version of [braintree-android](https://github.com/braintree/braintree_android) 3 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1String.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public interface ASN1String 4 | { 5 | public String getString(); 6 | } 7 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DEREncodable.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public interface DEREncodable 4 | { 5 | public DERObject getDERObject(); 6 | } 7 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | /** 4 | * basic interface for DER string objects. 5 | */ 6 | public interface DERString 7 | extends ASN1String 8 | { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 15 15:04:09 PST 2014 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip 7 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/InMemoryRepresentable.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public interface InMemoryRepresentable 6 | { 7 | DERObject getLoadedObject() 8 | throws IOException; 9 | } 10 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1OctetStringParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.InputStream; 4 | 5 | public interface ASN1OctetStringParser 6 | extends DEREncodable, InMemoryRepresentable 7 | { 8 | public InputStream getOctetStream(); 9 | } 10 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1SequenceParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public interface ASN1SequenceParser 6 | extends DEREncodable, InMemoryRepresentable 7 | { 8 | DEREncodable readObject() 9 | throws IOException; 10 | } 11 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1SetParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public interface ASN1SetParser 6 | extends DEREncodable, InMemoryRepresentable 7 | { 8 | public DEREncodable readObject() 9 | throws IOException; 10 | } 11 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERApplicationSpecific.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public class BERApplicationSpecific 4 | extends DERApplicationSpecific 5 | { 6 | public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec) 7 | { 8 | super(tagNo, vec); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/io/StreamOverflowException.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util.io; 2 | 3 | import java.io.IOException; 4 | 5 | public class StreamOverflowException 6 | extends IOException 7 | { 8 | public StreamOverflowException(String msg) 9 | { 10 | super(msg); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public interface ASN1ApplicationSpecificParser 6 | extends DEREncodable, InMemoryRepresentable 7 | { 8 | DEREncodable readObject() 9 | throws IOException; 10 | } 11 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Boolean.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public class ASN1Boolean 4 | extends DERBoolean 5 | { 6 | public ASN1Boolean(boolean value) 7 | { 8 | super(value); 9 | } 10 | 11 | ASN1Boolean(byte[] value) 12 | { 13 | super(value); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1TaggedObjectParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public interface ASN1TaggedObjectParser 6 | extends DEREncodable, InMemoryRepresentable 7 | { 8 | public int getTagNo(); 9 | 10 | public DEREncodable getObjectParser(int tag, boolean isExplicit) 11 | throws IOException; 12 | } 13 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintreegateway/encryption/BraintreeEncryptionException.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption; 2 | 3 | public class BraintreeEncryptionException extends Exception { 4 | public BraintreeEncryptionException(String message) { 5 | super(message); 6 | } 7 | 8 | public BraintreeEncryptionException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintreegateway/encryption/Random.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption; 2 | 3 | import java.security.SecureRandom; 4 | 5 | public final class Random { 6 | public static byte[] secureRandomBytes(int size) { 7 | PRNGFixes.apply(); 8 | SecureRandom random = new SecureRandom(); 9 | byte[] keyBytes = new byte[size]; 10 | random.nextBytes(keyBytes); 11 | return keyBytes; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1UTCTime.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.util.Date; 4 | 5 | public class ASN1UTCTime 6 | extends DERUTCTime 7 | { 8 | ASN1UTCTime(byte[] bytes) 9 | { 10 | super(bytes); 11 | } 12 | 13 | public ASN1UTCTime(Date time) 14 | { 15 | super(time); 16 | } 17 | 18 | public ASN1UTCTime(String time) 19 | { 20 | super(time); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Braintree Android Encryption 2 | 3 | This library is for use with [Braintree's payment gateway](http://braintreepayments.com/) in concert 4 | with one of [the supported client libraries](http://braintreepayments.com/docs). It encrypts 5 | sensitive payment information using the public key of an asymmetric key pair. 6 | 7 | # :warning: DEPRECATED :warning: 8 | This integration method is deprecated. Please upgrade to the latest version of [braintree-android](https://github.com/braintree/braintree_android) 9 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Integer.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.math.BigInteger; 4 | 5 | public class ASN1Integer 6 | extends DERInteger 7 | { 8 | ASN1Integer(byte[] bytes) 9 | { 10 | super(bytes); 11 | } 12 | 13 | public ASN1Integer(BigInteger value) 14 | { 15 | super(value); 16 | } 17 | 18 | public ASN1Integer(int value) 19 | { 20 | super(value); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Enumerated.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.math.BigInteger; 4 | 5 | public class ASN1Enumerated 6 | extends DEREnumerated 7 | { 8 | ASN1Enumerated(byte[] bytes) 9 | { 10 | super(bytes); 11 | } 12 | 13 | public ASN1Enumerated(BigInteger value) 14 | { 15 | super(value); 16 | } 17 | 18 | public ASN1Enumerated(int value) 19 | { 20 | super(value); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1GeneralizedTime.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.util.Date; 4 | 5 | public class ASN1GeneralizedTime 6 | extends DERGeneralizedTime 7 | { 8 | ASN1GeneralizedTime(byte[] bytes) 9 | { 10 | super(bytes); 11 | } 12 | 13 | public ASN1GeneralizedTime(Date time) 14 | { 15 | super(time); 16 | } 17 | 18 | public ASN1GeneralizedTime(String time) 19 | { 20 | super(time); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERObject.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public abstract class DERObject 6 | extends ASN1Encodable 7 | implements DERTags 8 | { 9 | public DERObject toASN1Object() 10 | { 11 | return this; 12 | } 13 | 14 | public abstract int hashCode(); 15 | 16 | public abstract boolean equals(Object o); 17 | 18 | abstract void encode(DEROutputStream out) 19 | throws IOException; 20 | } 21 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERNull.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * A NULL object. 7 | */ 8 | public class DERNull 9 | extends ASN1Null 10 | { 11 | public static final DERNull INSTANCE = new DERNull(); 12 | 13 | byte[] zeroBytes = new byte[0]; 14 | 15 | public DERNull() 16 | { 17 | } 18 | 19 | void encode( 20 | DEROutputStream out) 21 | throws IOException 22 | { 23 | out.writeEncoded(NULL, zeroBytes); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Choice.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | /** 4 | * Marker interface for CHOICE objects - if you implement this in a role your 5 | * own object any attempt to tag the object implicitly will convert the tag to 6 | * an explicit one as the encoding rules require. 7 | *

8 | * If you use this interface your class should also implement the getInstance 9 | * pattern which takes a tag object and the tagging mode used. 10 | */ 11 | public interface ASN1Choice 12 | { 13 | // marker interface 14 | } 15 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1ParsingException.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public class ASN1ParsingException 4 | extends IllegalStateException 5 | { 6 | private Throwable cause; 7 | 8 | ASN1ParsingException(String message) 9 | { 10 | super(message); 11 | } 12 | 13 | ASN1ParsingException(String message, Throwable cause) 14 | { 15 | super(message); 16 | this.cause = cause; 17 | } 18 | 19 | public Throwable getCause() 20 | { 21 | return cause; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Exception.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class ASN1Exception 6 | extends IOException 7 | { 8 | private Throwable cause; 9 | 10 | ASN1Exception(String message) 11 | { 12 | super(message); 13 | } 14 | 15 | ASN1Exception(String message, Throwable cause) 16 | { 17 | super(message); 18 | this.cause = cause; 19 | } 20 | 21 | public Throwable getCause() 22 | { 23 | return cause; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/encoders/Encoder.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util.encoders; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | /** 7 | * Encode and decode byte arrays (typically from binary to 7-bit ASCII 8 | * encodings). 9 | */ 10 | public interface Encoder 11 | { 12 | int encode(byte[] data, int off, int length, OutputStream out) throws IOException; 13 | 14 | int decode(byte[] data, int off, int length, OutputStream out) throws IOException; 15 | 16 | int decode(String data, OutputStream out) throws IOException; 17 | } 18 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1EncodableVector.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.util.Vector; 4 | 5 | /** 6 | * the parent class for this will eventually disappear. Use this one! 7 | */ 8 | public class ASN1EncodableVector 9 | extends DEREncodableVector 10 | { 11 | Vector v = new Vector(); 12 | 13 | public ASN1EncodableVector() 14 | { 15 | 16 | } 17 | 18 | public void add(DEREncodable obj) 19 | { 20 | v.addElement(obj); 21 | } 22 | 23 | public DEREncodable get(int i) 24 | { 25 | return (DEREncodable)v.elementAt(i); 26 | } 27 | 28 | public int size() 29 | { 30 | return v.size(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERFactory.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | class BERFactory 4 | { 5 | static final BERSequence EMPTY_SEQUENCE = new BERSequence(); 6 | static final BERSet EMPTY_SET = new BERSet(); 7 | 8 | static BERSequence createSequence(ASN1EncodableVector v) 9 | { 10 | return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v); 11 | } 12 | 13 | static BERSet createSet(ASN1EncodableVector v) 14 | { 15 | return v.size() < 1 ? EMPTY_SET : new BERSet(v); 16 | } 17 | 18 | static BERSet createSet(ASN1EncodableVector v, boolean needsSorting) 19 | { 20 | return v.size() < 1 ? EMPTY_SET : new BERSet(v, needsSorting); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERFactory.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | class DERFactory 4 | { 5 | static final DERSequence EMPTY_SEQUENCE = new DERSequence(); 6 | static final DERSet EMPTY_SET = new DERSet(); 7 | 8 | static DERSequence createSequence(ASN1EncodableVector v) 9 | { 10 | return v.size() < 1 ? EMPTY_SEQUENCE : new DERSequence(v); 11 | } 12 | 13 | static DERSet createSet(ASN1EncodableVector v) 14 | { 15 | return v.size() < 1 ? EMPTY_SET : new DERSet(v); 16 | } 17 | 18 | static DERSet createSet(ASN1EncodableVector v, boolean needsSorting) 19 | { 20 | return v.size() < 1 ? EMPTY_SET : new DERSet(v, needsSorting); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1ObjectIdentifier.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public class ASN1ObjectIdentifier 4 | extends DERObjectIdentifier 5 | { 6 | public ASN1ObjectIdentifier(String identifier) 7 | { 8 | super(identifier); 9 | } 10 | 11 | ASN1ObjectIdentifier(byte[] bytes) 12 | { 13 | super(bytes); 14 | } 15 | 16 | /** 17 | * Return an OID that creates a branch under the current one. 18 | * 19 | * @param branchID node numbers for the new branch. 20 | * @return 21 | */ 22 | public ASN1ObjectIdentifier branch(String branchID) 23 | { 24 | return new ASN1ObjectIdentifier(getId() + "." + branchID); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Null.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * A NULL object. 7 | */ 8 | public abstract class ASN1Null 9 | extends ASN1Object 10 | { 11 | public ASN1Null() 12 | { 13 | } 14 | 15 | public int hashCode() 16 | { 17 | return -1; 18 | } 19 | 20 | boolean asn1Equals( 21 | DERObject o) 22 | { 23 | if (!(o instanceof ASN1Null)) 24 | { 25 | return false; 26 | } 27 | 28 | return true; 29 | } 30 | 31 | abstract void encode(DEROutputStream out) 32 | throws IOException; 33 | 34 | public String toString() 35 | { 36 | return "NULL"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/LimitedInputStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.InputStream; 4 | 5 | abstract class LimitedInputStream 6 | extends InputStream 7 | { 8 | protected final InputStream _in; 9 | private int _limit; 10 | 11 | LimitedInputStream( 12 | InputStream in, 13 | int limit) 14 | { 15 | this._in = in; 16 | this._limit = limit; 17 | } 18 | 19 | int getRemaining() 20 | { 21 | // TODO: maybe one day this can become more accurate 22 | return _limit; 23 | } 24 | 25 | protected void setParentEofDetect(boolean on) 26 | { 27 | if (_in instanceof IndefiniteLengthInputStream) 28 | { 29 | ((IndefiniteLengthInputStream)_in).setEofOn00(on); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DEREncodableVector.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.util.Vector; 4 | 5 | /** 6 | * a general class for building up a vector of DER encodable objects - 7 | * this will eventually be superceded by ASN1EncodableVector so you should 8 | * use that class in preference. 9 | */ 10 | public class DEREncodableVector 11 | { 12 | Vector v = new Vector(); 13 | 14 | /** 15 | * @deprecated use ASN1EncodableVector instead. 16 | */ 17 | public DEREncodableVector() 18 | { 19 | 20 | } 21 | 22 | public void add( 23 | DEREncodable obj) 24 | { 25 | v.addElement(obj); 26 | } 27 | 28 | public DEREncodable get( 29 | int i) 30 | { 31 | return (DEREncodable)v.elementAt(i); 32 | } 33 | 34 | public int size() 35 | { 36 | return v.size(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DEROctetString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class DEROctetString 6 | extends ASN1OctetString 7 | { 8 | /** 9 | * @param string the octets making up the octet string. 10 | */ 11 | public DEROctetString( 12 | byte[] string) 13 | { 14 | super(string); 15 | } 16 | 17 | public DEROctetString( 18 | DEREncodable obj) 19 | { 20 | super(obj); 21 | } 22 | 23 | void encode( 24 | DEROutputStream out) 25 | throws IOException 26 | { 27 | out.writeEncoded(OCTET_STRING, string); 28 | } 29 | 30 | static void encode( 31 | DEROutputStream derOut, 32 | byte[] bytes) 33 | throws IOException 34 | { 35 | derOut.writeEncoded(DERTags.OCTET_STRING, bytes); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintreegateway/encryption/Braintree.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption; 2 | 3 | public class Braintree { 4 | private final String publicKey; 5 | 6 | public Braintree(String publicKey) { 7 | this.publicKey = publicKey; 8 | } 9 | 10 | public String getPublicKey() { 11 | return publicKey; 12 | } 13 | 14 | public String encrypt(String payload) throws BraintreeEncryptionException { 15 | byte[] aesKey = Random.secureRandomBytes(Aes.KEY_LENGTH); 16 | byte[] aesIV = Random.secureRandomBytes(Aes.IV_LENGTH); 17 | String encryptedPayload = Aes.encrypt(payload, aesKey, aesIV); 18 | String encryptedAesKey = Rsa.encrypt(aesKey, publicKey); 19 | return getPrefix() + encryptedAesKey + "$" + encryptedPayload; 20 | } 21 | 22 | private String getPrefix() { 23 | return "$bt3|android_" + BuildConfig.VERSION_NAME.replace(".", "_") + "$"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BEROutputStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public class BEROutputStream 7 | extends DEROutputStream 8 | { 9 | public BEROutputStream( 10 | OutputStream os) 11 | { 12 | super(os); 13 | } 14 | 15 | public void writeObject( 16 | Object obj) 17 | throws IOException 18 | { 19 | if (obj == null) 20 | { 21 | writeNull(); 22 | } 23 | else if (obj instanceof DERObject) 24 | { 25 | ((DERObject)obj).encode(this); 26 | } 27 | else if (obj instanceof DEREncodable) 28 | { 29 | ((DEREncodable)obj).getDERObject().encode(this); 30 | } 31 | else 32 | { 33 | throw new IOException("object not BEREncodable"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1OutputStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public class ASN1OutputStream 7 | extends DEROutputStream 8 | { 9 | public ASN1OutputStream( 10 | OutputStream os) 11 | { 12 | super(os); 13 | } 14 | 15 | public void writeObject( 16 | Object obj) 17 | throws IOException 18 | { 19 | if (obj == null) 20 | { 21 | writeNull(); 22 | } 23 | else if (obj instanceof DERObject) 24 | { 25 | ((DERObject)obj).encode(this); 26 | } 27 | else if (obj instanceof DEREncodable) 28 | { 29 | ((DEREncodable)obj).getDERObject().encode(this); 30 | } 31 | else 32 | { 33 | throw new IOException("object not ASN1Encodable"); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERSetParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class BERSetParser 6 | implements ASN1SetParser 7 | { 8 | private ASN1StreamParser _parser; 9 | 10 | BERSetParser(ASN1StreamParser parser) 11 | { 12 | this._parser = parser; 13 | } 14 | 15 | public DEREncodable readObject() 16 | throws IOException 17 | { 18 | return _parser.readObject(); 19 | } 20 | 21 | public DERObject getLoadedObject() 22 | throws IOException 23 | { 24 | return new BERSet(_parser.readVector(), false); 25 | } 26 | 27 | public DERObject getDERObject() 28 | { 29 | try 30 | { 31 | return getLoadedObject(); 32 | } 33 | catch (IOException e) 34 | { 35 | throw new ASN1ParsingException(e.getMessage(), e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERSetParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class DERSetParser 6 | implements ASN1SetParser 7 | { 8 | private ASN1StreamParser _parser; 9 | 10 | DERSetParser(ASN1StreamParser parser) 11 | { 12 | this._parser = parser; 13 | } 14 | 15 | public DEREncodable readObject() 16 | throws IOException 17 | { 18 | return _parser.readObject(); 19 | } 20 | 21 | public DERObject getLoadedObject() 22 | throws IOException 23 | { 24 | return new DERSet(_parser.readVector(), false); 25 | } 26 | 27 | public DERObject getDERObject() 28 | { 29 | try 30 | { 31 | return getLoadedObject(); 32 | } 33 | catch (IOException e) 34 | { 35 | throw new ASN1ParsingException(e.getMessage(), e); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERSequenceParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class DERSequenceParser 6 | implements ASN1SequenceParser 7 | { 8 | private ASN1StreamParser _parser; 9 | 10 | DERSequenceParser(ASN1StreamParser parser) 11 | { 12 | this._parser = parser; 13 | } 14 | 15 | public DEREncodable readObject() 16 | throws IOException 17 | { 18 | return _parser.readObject(); 19 | } 20 | 21 | public DERObject getLoadedObject() 22 | throws IOException 23 | { 24 | return new DERSequence(_parser.readVector()); 25 | } 26 | 27 | public DERObject getDERObject() 28 | { 29 | try 30 | { 31 | return getLoadedObject(); 32 | } 33 | catch (IOException e) 34 | { 35 | throw new IllegalStateException(e.getMessage()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERSequenceParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class BERSequenceParser 6 | implements ASN1SequenceParser 7 | { 8 | private ASN1StreamParser _parser; 9 | 10 | BERSequenceParser(ASN1StreamParser parser) 11 | { 12 | this._parser = parser; 13 | } 14 | 15 | public DEREncodable readObject() 16 | throws IOException 17 | { 18 | return _parser.readObject(); 19 | } 20 | 21 | public DERObject getLoadedObject() 22 | throws IOException 23 | { 24 | return new BERSequence(_parser.readVector()); 25 | } 26 | 27 | public DERObject getDERObject() 28 | { 29 | try 30 | { 31 | return getLoadedObject(); 32 | } 33 | catch (IOException e) 34 | { 35 | throw new IllegalStateException(e.getMessage()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DEROctetStringParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | public class DEROctetStringParser 7 | implements ASN1OctetStringParser 8 | { 9 | private DefiniteLengthInputStream stream; 10 | 11 | DEROctetStringParser( 12 | DefiniteLengthInputStream stream) 13 | { 14 | this.stream = stream; 15 | } 16 | 17 | public InputStream getOctetStream() 18 | { 19 | return stream; 20 | } 21 | 22 | public DERObject getLoadedObject() 23 | throws IOException 24 | { 25 | return new DEROctetString(stream.toByteArray()); 26 | } 27 | 28 | public DERObject getDERObject() 29 | { 30 | try 31 | { 32 | return getLoadedObject(); 33 | } 34 | catch (IOException e) 35 | { 36 | throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/LazyDERConstructionEnumeration.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.util.Enumeration; 4 | import java.io.IOException; 5 | 6 | class LazyDERConstructionEnumeration 7 | implements Enumeration 8 | { 9 | private ASN1InputStream aIn; 10 | private Object nextObj; 11 | 12 | public LazyDERConstructionEnumeration(byte[] encoded) 13 | { 14 | aIn = new ASN1InputStream(encoded, true); 15 | nextObj = readObject(); 16 | } 17 | 18 | public boolean hasMoreElements() 19 | { 20 | return nextObj != null; 21 | } 22 | 23 | public Object nextElement() 24 | { 25 | Object o = nextObj; 26 | 27 | nextObj = readObject(); 28 | 29 | return o; 30 | } 31 | 32 | private Object readObject() 33 | { 34 | try 35 | { 36 | return aIn.readObject(); 37 | } 38 | catch (IOException e) 39 | { 40 | throw new ASN1ParsingException("malformed DER construction: " + e, e); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERApplicationSpecificParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class BERApplicationSpecificParser 6 | implements ASN1ApplicationSpecificParser 7 | { 8 | private final int tag; 9 | private final ASN1StreamParser parser; 10 | 11 | BERApplicationSpecificParser(int tag, ASN1StreamParser parser) 12 | { 13 | this.tag = tag; 14 | this.parser = parser; 15 | } 16 | 17 | public DEREncodable readObject() 18 | throws IOException 19 | { 20 | return parser.readObject(); 21 | } 22 | 23 | public DERObject getLoadedObject() 24 | throws IOException 25 | { 26 | return new BERApplicationSpecific(tag, parser.readVector()); 27 | } 28 | 29 | public DERObject getDERObject() 30 | { 31 | try 32 | { 33 | return getLoadedObject(); 34 | } 35 | catch (IOException e) 36 | { 37 | throw new ASN1ParsingException(e.getMessage(), e); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2014 Braintree, a division of PayPal, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BEROctetStringParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | import com.braintree.org.bouncycastle.util.io.Streams; 7 | 8 | public class BEROctetStringParser 9 | implements ASN1OctetStringParser 10 | { 11 | private ASN1StreamParser _parser; 12 | 13 | BEROctetStringParser( 14 | ASN1StreamParser parser) 15 | { 16 | _parser = parser; 17 | } 18 | 19 | public InputStream getOctetStream() 20 | { 21 | return new ConstructedOctetStream(_parser); 22 | } 23 | 24 | public DERObject getLoadedObject() 25 | throws IOException 26 | { 27 | return new BERConstructedOctetString(Streams.readAll(getOctetStream())); 28 | } 29 | 30 | public DERObject getDERObject() 31 | { 32 | try 33 | { 34 | return getLoadedObject(); 35 | } 36 | catch (IOException e) 37 | { 38 | throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/OIDTokenizer.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | /** 4 | * class for breaking up an OID into it's component tokens, ala 5 | * java.util.StringTokenizer. We need this class as some of the 6 | * lightweight Java environment don't support classes like 7 | * StringTokenizer. 8 | */ 9 | public class OIDTokenizer 10 | { 11 | private String oid; 12 | private int index; 13 | 14 | public OIDTokenizer( 15 | String oid) 16 | { 17 | this.oid = oid; 18 | this.index = 0; 19 | } 20 | 21 | public boolean hasMoreTokens() 22 | { 23 | return (index != -1); 24 | } 25 | 26 | public String nextToken() 27 | { 28 | if (index == -1) 29 | { 30 | return null; 31 | } 32 | 33 | String token; 34 | int end = oid.indexOf('.', index); 35 | 36 | if (end == -1) 37 | { 38 | token = oid.substring(index); 39 | index = -1; 40 | return token; 41 | } 42 | 43 | token = oid.substring(index, end); 44 | 45 | index = end + 1; 46 | return token; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Object.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public abstract class ASN1Object 6 | extends DERObject 7 | { 8 | /** 9 | * Create a base ASN.1 object from a byte stream. 10 | * 11 | * @param data the byte stream to parse. 12 | * @return the base ASN.1 object represented by the byte stream. 13 | * @exception IOException if there is a problem parsing the data. 14 | */ 15 | public static ASN1Object fromByteArray(byte[] data) 16 | throws IOException 17 | { 18 | ASN1InputStream aIn = new ASN1InputStream(data); 19 | 20 | try 21 | { 22 | return (ASN1Object)aIn.readObject(); 23 | } 24 | catch (ClassCastException e) 25 | { 26 | throw new IOException("cannot recognise object in stream"); 27 | } 28 | } 29 | 30 | public final boolean equals(Object o) 31 | { 32 | if (this == o) 33 | { 34 | return true; 35 | } 36 | 37 | return (o instanceof DEREncodable) && asn1Equals(((DEREncodable)o).getDERObject()); 38 | } 39 | 40 | public abstract int hashCode(); 41 | 42 | abstract void encode(DEROutputStream out) throws IOException; 43 | 44 | abstract boolean asn1Equals(DERObject o); 45 | } 46 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERExternalParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class DERExternalParser 6 | implements DEREncodable, InMemoryRepresentable 7 | { 8 | private ASN1StreamParser _parser; 9 | 10 | /** 11 | * 12 | */ 13 | public DERExternalParser(ASN1StreamParser parser) 14 | { 15 | this._parser = parser; 16 | } 17 | 18 | public DEREncodable readObject() 19 | throws IOException 20 | { 21 | return _parser.readObject(); 22 | } 23 | 24 | public DERObject getLoadedObject() 25 | throws IOException 26 | { 27 | try 28 | { 29 | return new DERExternal(_parser.readVector()); 30 | } 31 | catch (IllegalArgumentException e) 32 | { 33 | throw new ASN1Exception(e.getMessage(), e); 34 | } 35 | } 36 | 37 | public DERObject getDERObject() 38 | { 39 | try 40 | { 41 | return getLoadedObject(); 42 | } 43 | catch (IOException ioe) 44 | { 45 | throw new ASN1ParsingException("unable to get DER object", ioe); 46 | } 47 | catch (IllegalArgumentException ioe) 48 | { 49 | throw new ASN1ParsingException("unable to get DER object", ioe); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERSequence.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.util.Enumeration; 5 | 6 | public class BERSequence 7 | extends DERSequence 8 | { 9 | /** 10 | * create an empty sequence 11 | */ 12 | public BERSequence() 13 | { 14 | } 15 | 16 | /** 17 | * create a sequence containing one object 18 | */ 19 | public BERSequence( 20 | DEREncodable obj) 21 | { 22 | super(obj); 23 | } 24 | 25 | /** 26 | * create a sequence containing a vector of objects. 27 | */ 28 | public BERSequence( 29 | ASN1EncodableVector v) 30 | { 31 | super(v); 32 | } 33 | 34 | /* 35 | */ 36 | void encode( 37 | DEROutputStream out) 38 | throws IOException 39 | { 40 | if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) 41 | { 42 | out.write(SEQUENCE | CONSTRUCTED); 43 | out.write(0x80); 44 | 45 | Enumeration e = getObjects(); 46 | while (e.hasMoreElements()) 47 | { 48 | out.writeObject(e.nextElement()); 49 | } 50 | 51 | out.write(0x00); 52 | out.write(0x00); 53 | } 54 | else 55 | { 56 | super.encode(out); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERSet.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.util.Enumeration; 5 | 6 | public class BERSet 7 | extends DERSet 8 | { 9 | /** 10 | * create an empty sequence 11 | */ 12 | public BERSet() 13 | { 14 | } 15 | 16 | /** 17 | * create a set containing one object 18 | */ 19 | public BERSet( 20 | DEREncodable obj) 21 | { 22 | super(obj); 23 | } 24 | 25 | /** 26 | * @param v - a vector of objects making up the set. 27 | */ 28 | public BERSet( 29 | ASN1EncodableVector v) 30 | { 31 | super(v, false); 32 | } 33 | 34 | /** 35 | * @param v - a vector of objects making up the set. 36 | */ 37 | BERSet( 38 | ASN1EncodableVector v, 39 | boolean needsSorting) 40 | { 41 | super(v, needsSorting); 42 | } 43 | 44 | /* 45 | */ 46 | void encode( 47 | DEROutputStream out) 48 | throws IOException 49 | { 50 | if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) 51 | { 52 | out.write(SET | CONSTRUCTED); 53 | out.write(0x80); 54 | 55 | Enumeration e = getObjects(); 56 | while (e.hasMoreElements()) 57 | { 58 | out.writeObject(e.nextElement()); 59 | } 60 | 61 | out.write(0x00); 62 | out.write(0x00); 63 | } 64 | else 65 | { 66 | super.encode(out); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/LazyDERSequence.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.util.Enumeration; 5 | 6 | public class LazyDERSequence 7 | extends DERSequence 8 | { 9 | private byte[] encoded; 10 | private boolean parsed = false; 11 | private int size = -1; 12 | 13 | LazyDERSequence( 14 | byte[] encoded) 15 | throws IOException 16 | { 17 | this.encoded = encoded; 18 | } 19 | 20 | private void parse() 21 | { 22 | Enumeration en = new LazyDERConstructionEnumeration(encoded); 23 | 24 | while (en.hasMoreElements()) 25 | { 26 | addObject((DEREncodable)en.nextElement()); 27 | } 28 | 29 | parsed = true; 30 | } 31 | 32 | public synchronized DEREncodable getObjectAt(int index) 33 | { 34 | if (!parsed) 35 | { 36 | parse(); 37 | } 38 | 39 | return super.getObjectAt(index); 40 | } 41 | 42 | public synchronized Enumeration getObjects() 43 | { 44 | if (parsed) 45 | { 46 | return super.getObjects(); 47 | } 48 | 49 | return new LazyDERConstructionEnumeration(encoded); 50 | } 51 | 52 | public int size() 53 | { 54 | if (size < 0) 55 | { 56 | Enumeration en = new LazyDERConstructionEnumeration(encoded); 57 | 58 | size = 0; 59 | while (en.hasMoreElements()) 60 | { 61 | en.nextElement(); 62 | size++; 63 | } 64 | } 65 | 66 | return size; 67 | } 68 | 69 | void encode( 70 | DEROutputStream out) 71 | throws IOException 72 | { 73 | out.writeEncoded(SEQUENCE | CONSTRUCTED, encoded); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERTags.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | public interface DERTags 4 | { 5 | public static final int BOOLEAN = 0x01; 6 | public static final int INTEGER = 0x02; 7 | public static final int BIT_STRING = 0x03; 8 | public static final int OCTET_STRING = 0x04; 9 | public static final int NULL = 0x05; 10 | public static final int OBJECT_IDENTIFIER = 0x06; 11 | public static final int EXTERNAL = 0x08; 12 | public static final int ENUMERATED = 0x0a; 13 | public static final int SEQUENCE = 0x10; 14 | public static final int SEQUENCE_OF = 0x10; // for completeness 15 | public static final int SET = 0x11; 16 | public static final int SET_OF = 0x11; // for completeness 17 | 18 | 19 | public static final int NUMERIC_STRING = 0x12; 20 | public static final int PRINTABLE_STRING = 0x13; 21 | public static final int T61_STRING = 0x14; 22 | public static final int VIDEOTEX_STRING = 0x15; 23 | public static final int IA5_STRING = 0x16; 24 | public static final int UTC_TIME = 0x17; 25 | public static final int GENERALIZED_TIME = 0x18; 26 | public static final int GRAPHIC_STRING = 0x19; 27 | public static final int VISIBLE_STRING = 0x1a; 28 | public static final int GENERAL_STRING = 0x1b; 29 | public static final int UNIVERSAL_STRING = 0x1c; 30 | public static final int BMP_STRING = 0x1e; 31 | public static final int UTF8_STRING = 0x0c; 32 | 33 | public static final int CONSTRUCTED = 0x20; 34 | public static final int APPLICATION = 0x40; 35 | public static final int TAGGED = 0x80; 36 | } 37 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERUnknownTag.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | import com.braintree.org.bouncycastle.util.Arrays; 6 | 7 | /** 8 | * We insert one of these when we find a tag we don't recognise. 9 | */ 10 | public class DERUnknownTag 11 | extends DERObject 12 | { 13 | private boolean isConstructed; 14 | private int tag; 15 | private byte[] data; 16 | 17 | /** 18 | * @param tag the tag value. 19 | * @param data the contents octets. 20 | */ 21 | public DERUnknownTag( 22 | int tag, 23 | byte[] data) 24 | { 25 | this(false, tag, data); 26 | } 27 | 28 | public DERUnknownTag( 29 | boolean isConstructed, 30 | int tag, 31 | byte[] data) 32 | { 33 | this.isConstructed = isConstructed; 34 | this.tag = tag; 35 | this.data = data; 36 | } 37 | 38 | public boolean isConstructed() 39 | { 40 | return isConstructed; 41 | } 42 | 43 | public int getTag() 44 | { 45 | return tag; 46 | } 47 | 48 | public byte[] getData() 49 | { 50 | return data; 51 | } 52 | 53 | void encode( 54 | DEROutputStream out) 55 | throws IOException 56 | { 57 | out.writeEncoded(isConstructed ? DERTags.CONSTRUCTED : 0, tag, data); 58 | } 59 | 60 | public boolean equals( 61 | Object o) 62 | { 63 | if (!(o instanceof DERUnknownTag)) 64 | { 65 | return false; 66 | } 67 | 68 | DERUnknownTag other = (DERUnknownTag)o; 69 | 70 | return isConstructed == other.isConstructed 71 | && tag == other.tag 72 | && Arrays.areEqual(data, other.data); 73 | } 74 | 75 | public int hashCode() 76 | { 77 | return (isConstructed ? ~0 : 0) ^ tag ^ Arrays.hashCode(data); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | task :default => [:test] 4 | 5 | desc "run unit tests" 6 | task :test do 7 | output = `adb devices` 8 | if output.match(/device$/) 9 | sh "./gradlew --info clean lint connectedAndroidTest" 10 | else 11 | puts "Please connect a device or start an emulator and try again" 12 | exit 1 13 | end 14 | end 15 | 16 | task :release => :test do 17 | last_version = `git tag | tail -1`.chomp 18 | puts "Changes since #{last_version}:" 19 | sh "git log --pretty=format:\"%h %ad%x20%s%x20%x28%an%x29\" --date=short #{last_version}.." 20 | $stdin.gets 21 | 22 | puts "What version are you releasing? (x.x.x format)" 23 | version = $stdin.gets.chomp 24 | 25 | increment_version_code 26 | update_version(version) 27 | 28 | sh "./gradlew clean uploadArchives" 29 | puts "BraintreeAndroidEncryption #{version} was uploaded, please promote it on oss.sonatype.org. Press ENTER when you have promoted it" 30 | $stdin.gets 31 | 32 | sh "git commit -am 'Release #{version}'" 33 | sh "git tag #{version} -am '#{version}'" 34 | 35 | puts "Commits and tags have been created. If everything appears to be in order, hit ENTER to push." 36 | $stdin.gets 37 | 38 | sh "git push origin master" 39 | sh "git push --tags" 40 | 41 | puts "Tagging complete! Commits and tags are now in GHE." 42 | puts "Push to public Github and update releases with this release." 43 | end 44 | 45 | def build_gradle_file 46 | 'BraintreeAndroidEncryption/build.gradle' 47 | end 48 | 49 | def increment_version_code 50 | new_build_file = "" 51 | File.foreach(build_gradle_file) do |line| 52 | if line.match(/versionCode (\d+)/) 53 | new_build_file += line.gsub(/versionCode \d+/, "versionCode #{$1.to_i + 1}") 54 | else 55 | new_build_file += line 56 | end 57 | end 58 | IO.write(build_gradle_file, new_build_file) 59 | end 60 | 61 | def update_version(version) 62 | IO.write(build_gradle_file, 63 | File.open(build_gradle_file) do |file| 64 | file.read.gsub(/versionName '\d+\.\d+\.\d+'/, "versionName '#{version}'") 65 | end 66 | ) 67 | end 68 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERTaggedObjectParser.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | 6 | public class BERTaggedObjectParser 7 | implements ASN1TaggedObjectParser 8 | { 9 | private boolean _constructed; 10 | private int _tagNumber; 11 | private ASN1StreamParser _parser; 12 | 13 | /** 14 | * @deprecated 15 | */ 16 | protected BERTaggedObjectParser( 17 | int baseTag, 18 | int tagNumber, 19 | InputStream contentStream) 20 | { 21 | this((baseTag & DERTags.CONSTRUCTED) != 0, tagNumber, new ASN1StreamParser(contentStream)); 22 | } 23 | 24 | BERTaggedObjectParser( 25 | boolean constructed, 26 | int tagNumber, 27 | ASN1StreamParser parser) 28 | { 29 | _constructed = constructed; 30 | _tagNumber = tagNumber; 31 | _parser = parser; 32 | } 33 | 34 | public boolean isConstructed() 35 | { 36 | return _constructed; 37 | } 38 | 39 | public int getTagNo() 40 | { 41 | return _tagNumber; 42 | } 43 | 44 | public DEREncodable getObjectParser( 45 | int tag, 46 | boolean isExplicit) 47 | throws IOException 48 | { 49 | if (isExplicit) 50 | { 51 | if (!_constructed) 52 | { 53 | throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)"); 54 | } 55 | return _parser.readObject(); 56 | } 57 | 58 | return _parser.readImplicit(_constructed, tag); 59 | } 60 | 61 | public DERObject getLoadedObject() 62 | throws IOException 63 | { 64 | return _parser.readTaggedObject(_constructed, _tagNumber); 65 | } 66 | 67 | public DERObject getDERObject() 68 | { 69 | try 70 | { 71 | return this.getLoadedObject(); 72 | } 73 | catch (IOException e) 74 | { 75 | throw new ASN1ParsingException(e.getMessage()); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/androidTest/java/com/braintreegateway/encryption/util/RsaDecrypter.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption.util; 2 | 3 | import static javax.crypto.Cipher.getInstance; 4 | import java.security.InvalidKeyException; 5 | import java.security.spec.InvalidKeySpecException; 6 | import java.security.KeyFactory; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.security.NoSuchProviderException; 9 | import java.security.PrivateKey; 10 | import java.security.spec.PKCS8EncodedKeySpec; 11 | import javax.crypto.BadPaddingException; 12 | import javax.crypto.Cipher; 13 | import javax.crypto.IllegalBlockSizeException; 14 | import javax.crypto.NoSuchPaddingException; 15 | import com.braintree.org.bouncycastle.util.encoders.Base64; 16 | 17 | public final class RsaDecrypter { 18 | public static byte[] decrypt(String encryptedData, String privateKey) throws NoSuchAlgorithmException, 19 | InvalidKeySpecException, 20 | NoSuchAlgorithmException, 21 | InvalidKeyException, 22 | IllegalBlockSizeException, 23 | NoSuchProviderException, 24 | NoSuchPaddingException, 25 | BadPaddingException { 26 | byte[] keyBytes = Base64.decode(privateKey); 27 | KeyFactory keyFactory; 28 | keyFactory = KeyFactory.getInstance("RSA", "BC"); 29 | PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); 30 | PrivateKey privKey = keyFactory.generatePrivate(encodedKeySpec); 31 | Cipher rsa = getInstance("RSA/ECB/PKCS1Padding"); 32 | rsa.init(Cipher.DECRYPT_MODE, privKey); 33 | byte[] decodedEncrypted = Base64.decode(encryptedData); 34 | return rsa.doFinal(decodedEncrypted); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERSequence.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.util.Enumeration; 6 | 7 | public class DERSequence 8 | extends ASN1Sequence 9 | { 10 | /** 11 | * create an empty sequence 12 | */ 13 | public DERSequence() 14 | { 15 | } 16 | 17 | /** 18 | * create a sequence containing one object 19 | */ 20 | public DERSequence( 21 | DEREncodable obj) 22 | { 23 | this.addObject(obj); 24 | } 25 | 26 | /** 27 | * create a sequence containing a vector of objects. 28 | */ 29 | public DERSequence( 30 | ASN1EncodableVector v) 31 | { 32 | for (int i = 0; i != v.size(); i++) 33 | { 34 | this.addObject(v.get(i)); 35 | } 36 | } 37 | 38 | /** 39 | * create a sequence containing an array of objects. 40 | */ 41 | public DERSequence( 42 | ASN1Encodable[] a) 43 | { 44 | for (int i = 0; i != a.length; i++) 45 | { 46 | this.addObject(a[i]); 47 | } 48 | } 49 | 50 | /* 51 | * A note on the implementation: 52 | *

53 | * As DER requires the constructed, definite-length model to 54 | * be used for structured types, this varies slightly from the 55 | * ASN.1 descriptions given. Rather than just outputing SEQUENCE, 56 | * we also have to specify CONSTRUCTED, and the objects length. 57 | */ 58 | void encode( 59 | DEROutputStream out) 60 | throws IOException 61 | { 62 | // TODO Intermediate buffer could be avoided if we could calculate expected length 63 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 64 | DEROutputStream dOut = new DEROutputStream(bOut); 65 | Enumeration e = this.getObjects(); 66 | 67 | while (e.hasMoreElements()) 68 | { 69 | Object obj = e.nextElement(); 70 | 71 | dOut.writeObject(obj); 72 | } 73 | 74 | dOut.close(); 75 | 76 | byte[] bytes = bOut.toByteArray(); 77 | 78 | out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/androidTest/java/com/braintreegateway/encryption/test/AesTest.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption.test; 2 | 3 | import java.util.Arrays; 4 | import java.security.InvalidAlgorithmParameterException; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.InvalidKeyException; 7 | import javax.crypto.IllegalBlockSizeException; 8 | import javax.crypto.BadPaddingException; 9 | import javax.crypto.NoSuchPaddingException; 10 | import android.test.AndroidTestCase; 11 | import com.braintree.org.bouncycastle.util.encoders.Base64; 12 | import com.braintreegateway.encryption.Aes; 13 | import com.braintreegateway.encryption.Random; 14 | import com.braintreegateway.encryption.BraintreeEncryptionException; 15 | import com.braintreegateway.encryption.util.AesDecrypter; 16 | 17 | public class AesTest extends AndroidTestCase { 18 | private byte[] aesKey; 19 | private byte[] aesIV; 20 | private final String dataToEncrypt = "test data"; 21 | 22 | @Override 23 | public void setUp() { 24 | aesKey = Random.secureRandomBytes(Aes.KEY_LENGTH); 25 | aesIV = Random.secureRandomBytes(Aes.IV_LENGTH); 26 | } 27 | 28 | public void testAesEncryptionSize() throws BraintreeEncryptionException { 29 | String encryptedData = Aes.encrypt(dataToEncrypt, aesKey, aesIV); 30 | assertEquals(44, encryptedData.length()); 31 | assertTrue(encryptedData.substring(43, 44).equals("=")); 32 | assertFalse(encryptedData.substring(42, 43).equals("=")); 33 | } 34 | 35 | public void testAesEncryption() throws BraintreeEncryptionException, 36 | InvalidKeyException, 37 | IllegalBlockSizeException, 38 | BadPaddingException, 39 | InvalidAlgorithmParameterException, 40 | NoSuchAlgorithmException, 41 | NoSuchPaddingException { 42 | String encryptedData = Aes.encrypt(dataToEncrypt, aesKey, aesIV); 43 | byte[] decryptedData = AesDecrypter.decrypt(encryptedData, Base64.encode(aesKey), aesIV); 44 | assertTrue(Arrays.equals(dataToEncrypt.getBytes(), decryptedData)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERTaggedObject.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER TaggedObject - in ASN.1 notation this is any object preceded by 7 | * a [n] where n is some number - these are assumed to follow the construction 8 | * rules (as with sequences). 9 | */ 10 | public class DERTaggedObject 11 | extends ASN1TaggedObject 12 | { 13 | private static final byte[] ZERO_BYTES = new byte[0]; 14 | 15 | /** 16 | * @param tagNo the tag number for this object. 17 | * @param obj the tagged object. 18 | */ 19 | public DERTaggedObject( 20 | int tagNo, 21 | DEREncodable obj) 22 | { 23 | super(tagNo, obj); 24 | } 25 | 26 | /** 27 | * @param explicit true if an explicitly tagged object. 28 | * @param tagNo the tag number for this object. 29 | * @param obj the tagged object. 30 | */ 31 | public DERTaggedObject( 32 | boolean explicit, 33 | int tagNo, 34 | DEREncodable obj) 35 | { 36 | super(explicit, tagNo, obj); 37 | } 38 | 39 | /** 40 | * create an implicitly tagged object that contains a zero 41 | * length sequence. 42 | */ 43 | public DERTaggedObject( 44 | int tagNo) 45 | { 46 | super(false, tagNo, new DERSequence()); 47 | } 48 | 49 | void encode( 50 | DEROutputStream out) 51 | throws IOException 52 | { 53 | if (!empty) 54 | { 55 | byte[] bytes = obj.getDERObject().getEncoded(DER); 56 | 57 | if (explicit) 58 | { 59 | out.writeEncoded(CONSTRUCTED | TAGGED, tagNo, bytes); 60 | } 61 | else 62 | { 63 | // 64 | // need to mark constructed types... 65 | // 66 | int flags; 67 | if ((bytes[0] & CONSTRUCTED) != 0) 68 | { 69 | flags = CONSTRUCTED | TAGGED; 70 | } 71 | else 72 | { 73 | flags = TAGGED; 74 | } 75 | 76 | out.writeTag(flags, tagNo); 77 | out.write(bytes, 1, bytes.length - 1); 78 | } 79 | } 80 | else 81 | { 82 | out.writeEncoded(CONSTRUCTED | TAGGED, tagNo, ZERO_BYTES); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERGeneralString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class DERGeneralString 6 | extends ASN1Object implements DERString 7 | { 8 | private String string; 9 | 10 | public static DERGeneralString getInstance( 11 | Object obj) 12 | { 13 | if (obj == null || obj instanceof DERGeneralString) 14 | { 15 | return (DERGeneralString) obj; 16 | } 17 | 18 | throw new IllegalArgumentException("illegal object in getInstance: " 19 | + obj.getClass().getName()); 20 | } 21 | 22 | public static DERGeneralString getInstance( 23 | ASN1TaggedObject obj, 24 | boolean explicit) 25 | { 26 | DERObject o = obj.getObject(); 27 | 28 | if (explicit || o instanceof DERGeneralString) 29 | { 30 | return getInstance(o); 31 | } 32 | else 33 | { 34 | return new DERGeneralString(((ASN1OctetString)o).getOctets()); 35 | } 36 | } 37 | 38 | public DERGeneralString(byte[] string) 39 | { 40 | char[] cs = new char[string.length]; 41 | for (int i = 0; i != cs.length; i++) 42 | { 43 | cs[i] = (char)(string[i] & 0xff); 44 | } 45 | this.string = new String(cs); 46 | } 47 | 48 | public DERGeneralString(String string) 49 | { 50 | this.string = string; 51 | } 52 | 53 | public String getString() 54 | { 55 | return string; 56 | } 57 | 58 | public String toString() 59 | { 60 | return string; 61 | } 62 | 63 | public byte[] getOctets() 64 | { 65 | char[] cs = string.toCharArray(); 66 | byte[] bs = new byte[cs.length]; 67 | for (int i = 0; i != cs.length; i++) 68 | { 69 | bs[i] = (byte) cs[i]; 70 | } 71 | return bs; 72 | } 73 | 74 | void encode(DEROutputStream out) 75 | throws IOException 76 | { 77 | out.writeEncoded(GENERAL_STRING, this.getOctets()); 78 | } 79 | 80 | public int hashCode() 81 | { 82 | return this.getString().hashCode(); 83 | } 84 | 85 | boolean asn1Equals(DERObject o) 86 | { 87 | if (!(o instanceof DERGeneralString)) 88 | { 89 | return false; 90 | } 91 | DERGeneralString s = (DERGeneralString) o; 92 | return this.getString().equals(s.getString()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintreegateway/encryption/Aes.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption; 2 | 3 | import com.braintree.org.bouncycastle.util.encoders.Base64; 4 | 5 | import java.security.InvalidAlgorithmParameterException; 6 | import java.security.InvalidKeyException; 7 | import java.security.NoSuchAlgorithmException; 8 | import java.util.Arrays; 9 | 10 | import javax.crypto.BadPaddingException; 11 | import javax.crypto.Cipher; 12 | import javax.crypto.IllegalBlockSizeException; 13 | import javax.crypto.NoSuchPaddingException; 14 | import javax.crypto.spec.IvParameterSpec; 15 | import javax.crypto.spec.SecretKeySpec; 16 | 17 | public final class Aes { 18 | private static final String ALGORITHM = "AES"; 19 | private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding"; 20 | public static final int KEY_LENGTH = 32; 21 | public static final int IV_LENGTH = 16; 22 | 23 | public static String encrypt(String data, byte[] aesKey, byte[] iv) throws BraintreeEncryptionException { 24 | SecretKeySpec key = new SecretKeySpec(aesKey, ALGORITHM); 25 | Cipher cipher = aesCipher(); 26 | try { 27 | IvParameterSpec ivParamSpec = new IvParameterSpec(iv); 28 | cipher.init(Cipher.ENCRYPT_MODE, key, ivParamSpec); 29 | byte[] encryptedBytes = cipher.doFinal(data.getBytes()); 30 | byte[] buffer = Arrays.copyOf(iv, iv.length + encryptedBytes.length); 31 | System.arraycopy(encryptedBytes, 0, buffer, iv.length, encryptedBytes.length); 32 | return new String(Base64.encode(buffer)); 33 | } catch (InvalidKeyException e) { 34 | throw new BraintreeEncryptionException("Invalid Key: " + e.getMessage()); 35 | } catch (BadPaddingException e) { 36 | throw new BraintreeEncryptionException("Bad Padding: " + e.getMessage()); 37 | } catch (IllegalBlockSizeException e) { 38 | throw new BraintreeEncryptionException("Illegal Block Size: " + e.getMessage()); 39 | } catch (InvalidAlgorithmParameterException e) { 40 | throw new BraintreeEncryptionException("Invalid Algorithm: " + e.getMessage()); 41 | } 42 | } 43 | 44 | private static Cipher aesCipher() throws BraintreeEncryptionException { 45 | try { 46 | return Cipher.getInstance(TRANSFORMATION); 47 | } catch (NoSuchAlgorithmException e) { 48 | throw new BraintreeEncryptionException("No Such Algorithm: " + e.getMessage()); 49 | } catch (NoSuchPaddingException e) { 50 | throw new BraintreeEncryptionException("No Such Padding: " + e.getMessage()); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/io/Streams.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util.io; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | 8 | public final class Streams 9 | { 10 | private static int BUFFER_SIZE = 512; 11 | 12 | public static void drain(InputStream inStr) 13 | throws IOException 14 | { 15 | byte[] bs = new byte[BUFFER_SIZE]; 16 | while (inStr.read(bs, 0, bs.length) >= 0) 17 | { 18 | } 19 | } 20 | 21 | public static byte[] readAll(InputStream inStr) 22 | throws IOException 23 | { 24 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 25 | pipeAll(inStr, buf); 26 | return buf.toByteArray(); 27 | } 28 | 29 | public static byte[] readAllLimited(InputStream inStr, int limit) 30 | throws IOException 31 | { 32 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 33 | pipeAllLimited(inStr, limit, buf); 34 | return buf.toByteArray(); 35 | } 36 | 37 | public static int readFully(InputStream inStr, byte[] buf) 38 | throws IOException 39 | { 40 | return readFully(inStr, buf, 0, buf.length); 41 | } 42 | 43 | public static int readFully(InputStream inStr, byte[] buf, int off, int len) 44 | throws IOException 45 | { 46 | int totalRead = 0; 47 | while (totalRead < len) 48 | { 49 | int numRead = inStr.read(buf, off + totalRead, len - totalRead); 50 | if (numRead < 0) 51 | { 52 | break; 53 | } 54 | totalRead += numRead; 55 | } 56 | return totalRead; 57 | } 58 | 59 | public static void pipeAll(InputStream inStr, OutputStream outStr) 60 | throws IOException 61 | { 62 | byte[] bs = new byte[BUFFER_SIZE]; 63 | int numRead; 64 | while ((numRead = inStr.read(bs, 0, bs.length)) >= 0) 65 | { 66 | outStr.write(bs, 0, numRead); 67 | } 68 | } 69 | 70 | public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr) 71 | throws IOException 72 | { 73 | long total = 0; 74 | byte[] bs = new byte[BUFFER_SIZE]; 75 | int numRead; 76 | while ((numRead = inStr.read(bs, 0, bs.length)) >= 0) 77 | { 78 | total += numRead; 79 | if (total > limit) 80 | { 81 | throw new StreamOverflowException("Data Overflow"); 82 | } 83 | outStr.write(bs, 0, numRead); 84 | } 85 | return total; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERSet.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.util.Enumeration; 6 | 7 | /** 8 | * A DER encoded set object 9 | */ 10 | public class DERSet 11 | extends ASN1Set 12 | { 13 | /** 14 | * create an empty set 15 | */ 16 | public DERSet() 17 | { 18 | } 19 | 20 | /** 21 | * @param obj - a single object that makes up the set. 22 | */ 23 | public DERSet( 24 | DEREncodable obj) 25 | { 26 | this.addObject(obj); 27 | } 28 | 29 | /** 30 | * @param v - a vector of objects making up the set. 31 | */ 32 | public DERSet( 33 | ASN1EncodableVector v) 34 | { 35 | this(v, true); 36 | } 37 | 38 | /** 39 | * create a set from an array of objects. 40 | */ 41 | public DERSet( 42 | ASN1Encodable[] a) 43 | { 44 | for (int i = 0; i != a.length; i++) 45 | { 46 | this.addObject(a[i]); 47 | } 48 | 49 | this.sort(); 50 | } 51 | 52 | /** 53 | * @param v - a vector of objects making up the set. 54 | */ 55 | DERSet( 56 | ASN1EncodableVector v, 57 | boolean needsSorting) 58 | { 59 | for (int i = 0; i != v.size(); i++) 60 | { 61 | this.addObject(v.get(i)); 62 | } 63 | 64 | if (needsSorting) 65 | { 66 | this.sort(); 67 | } 68 | } 69 | 70 | /* 71 | * A note on the implementation: 72 | *

73 | * As DER requires the constructed, definite-length model to 74 | * be used for structured types, this varies slightly from the 75 | * ASN.1 descriptions given. Rather than just outputing SET, 76 | * we also have to specify CONSTRUCTED, and the objects length. 77 | */ 78 | void encode( 79 | DEROutputStream out) 80 | throws IOException 81 | { 82 | // TODO Intermediate buffer could be avoided if we could calculate expected length 83 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 84 | DEROutputStream dOut = new DEROutputStream(bOut); 85 | Enumeration e = this.getObjects(); 86 | 87 | while (e.hasMoreElements()) 88 | { 89 | Object obj = e.nextElement(); 90 | 91 | dOut.writeObject(obj); 92 | } 93 | 94 | dOut.close(); 95 | 96 | byte[] bytes = bOut.toByteArray(); 97 | 98 | out.writeEncoded(SET | CONSTRUCTED, bytes); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/IndefiniteLengthInputStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | class IndefiniteLengthInputStream 8 | extends LimitedInputStream 9 | { 10 | private int _b1; 11 | private int _b2; 12 | private boolean _eofReached = false; 13 | private boolean _eofOn00 = true; 14 | 15 | IndefiniteLengthInputStream( 16 | InputStream in, 17 | int limit) 18 | throws IOException 19 | { 20 | super(in, limit); 21 | 22 | _b1 = in.read(); 23 | _b2 = in.read(); 24 | 25 | if (_b2 < 0) 26 | { 27 | // Corrupted stream 28 | throw new EOFException(); 29 | } 30 | 31 | checkForEof(); 32 | } 33 | 34 | void setEofOn00( 35 | boolean eofOn00) 36 | { 37 | _eofOn00 = eofOn00; 38 | checkForEof(); 39 | } 40 | 41 | private boolean checkForEof() 42 | { 43 | if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) 44 | { 45 | _eofReached = true; 46 | setParentEofDetect(true); 47 | } 48 | return _eofReached; 49 | } 50 | 51 | public int read(byte[] b, int off, int len) 52 | throws IOException 53 | { 54 | // Only use this optimisation if we aren't checking for 00 55 | if (_eofOn00 || len < 3) 56 | { 57 | return super.read(b, off, len); 58 | } 59 | 60 | if (_eofReached) 61 | { 62 | return -1; 63 | } 64 | 65 | int numRead = _in.read(b, off + 2, len - 2); 66 | 67 | if (numRead < 0) 68 | { 69 | // Corrupted stream 70 | throw new EOFException(); 71 | } 72 | 73 | b[off] = (byte)_b1; 74 | b[off + 1] = (byte)_b2; 75 | 76 | _b1 = _in.read(); 77 | _b2 = _in.read(); 78 | 79 | if (_b2 < 0) 80 | { 81 | // Corrupted stream 82 | throw new EOFException(); 83 | } 84 | 85 | return numRead + 2; 86 | } 87 | 88 | public int read() 89 | throws IOException 90 | { 91 | if (checkForEof()) 92 | { 93 | return -1; 94 | } 95 | 96 | int b = _in.read(); 97 | 98 | if (b < 0) 99 | { 100 | // Corrupted stream 101 | throw new EOFException(); 102 | } 103 | 104 | int v = _b1; 105 | 106 | _b1 = _b2; 107 | _b2 = b; 108 | 109 | return v; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DEREnumerated.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.math.BigInteger; 5 | 6 | import com.braintree.org.bouncycastle.util.Arrays; 7 | 8 | public class DEREnumerated 9 | extends ASN1Object 10 | { 11 | byte[] bytes; 12 | 13 | /** 14 | * return an integer from the passed in object 15 | * 16 | * @exception IllegalArgumentException if the object cannot be converted. 17 | */ 18 | public static DEREnumerated getInstance( 19 | Object obj) 20 | { 21 | if (obj == null || obj instanceof DEREnumerated) 22 | { 23 | return (DEREnumerated)obj; 24 | } 25 | 26 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 27 | } 28 | 29 | /** 30 | * return an Enumerated from a tagged object. 31 | * 32 | * @param obj the tagged object holding the object we want 33 | * @param explicit true if the object is meant to be explicitly 34 | * tagged false otherwise. 35 | * @exception IllegalArgumentException if the tagged object cannot 36 | * be converted. 37 | */ 38 | public static DEREnumerated getInstance( 39 | ASN1TaggedObject obj, 40 | boolean explicit) 41 | { 42 | DERObject o = obj.getObject(); 43 | 44 | if (explicit || o instanceof DEREnumerated) 45 | { 46 | return getInstance(o); 47 | } 48 | else 49 | { 50 | return new DEREnumerated(((ASN1OctetString)o).getOctets()); 51 | } 52 | } 53 | 54 | public DEREnumerated( 55 | int value) 56 | { 57 | bytes = BigInteger.valueOf(value).toByteArray(); 58 | } 59 | 60 | public DEREnumerated( 61 | BigInteger value) 62 | { 63 | bytes = value.toByteArray(); 64 | } 65 | 66 | public DEREnumerated( 67 | byte[] bytes) 68 | { 69 | this.bytes = bytes; 70 | } 71 | 72 | public BigInteger getValue() 73 | { 74 | return new BigInteger(bytes); 75 | } 76 | 77 | void encode( 78 | DEROutputStream out) 79 | throws IOException 80 | { 81 | out.writeEncoded(ENUMERATED, bytes); 82 | } 83 | 84 | boolean asn1Equals( 85 | DERObject o) 86 | { 87 | if (!(o instanceof DEREnumerated)) 88 | { 89 | return false; 90 | } 91 | 92 | DEREnumerated other = (DEREnumerated)o; 93 | 94 | return Arrays.areEqual(this.bytes, other.bytes); 95 | } 96 | 97 | public int hashCode() 98 | { 99 | return Arrays.hashCode(bytes); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DefiniteLengthInputStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.EOFException; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | import com.braintree.org.bouncycastle.util.io.Streams; 8 | 9 | class DefiniteLengthInputStream 10 | extends LimitedInputStream 11 | { 12 | private static final byte[] EMPTY_BYTES = new byte[0]; 13 | 14 | private final int _originalLength; 15 | private int _remaining; 16 | 17 | DefiniteLengthInputStream( 18 | InputStream in, 19 | int length) 20 | { 21 | super(in, length); 22 | 23 | if (length < 0) 24 | { 25 | throw new IllegalArgumentException("negative lengths not allowed"); 26 | } 27 | 28 | this._originalLength = length; 29 | this._remaining = length; 30 | 31 | if (length == 0) 32 | { 33 | setParentEofDetect(true); 34 | } 35 | } 36 | 37 | int getRemaining() 38 | { 39 | return _remaining; 40 | } 41 | 42 | public int read() 43 | throws IOException 44 | { 45 | if (_remaining == 0) 46 | { 47 | return -1; 48 | } 49 | 50 | int b = _in.read(); 51 | 52 | if (b < 0) 53 | { 54 | throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); 55 | } 56 | 57 | if (--_remaining == 0) 58 | { 59 | setParentEofDetect(true); 60 | } 61 | 62 | return b; 63 | } 64 | 65 | public int read(byte[] buf, int off, int len) 66 | throws IOException 67 | { 68 | if (_remaining == 0) 69 | { 70 | return -1; 71 | } 72 | 73 | int toRead = Math.min(len, _remaining); 74 | int numRead = _in.read(buf, off, toRead); 75 | 76 | if (numRead < 0) 77 | { 78 | throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); 79 | } 80 | 81 | if ((_remaining -= numRead) == 0) 82 | { 83 | setParentEofDetect(true); 84 | } 85 | 86 | return numRead; 87 | } 88 | 89 | byte[] toByteArray() 90 | throws IOException 91 | { 92 | if (_remaining == 0) 93 | { 94 | return EMPTY_BYTES; 95 | } 96 | 97 | byte[] bytes = new byte[_remaining]; 98 | if ((_remaining -= Streams.readFully(_in, bytes)) != 0) 99 | { 100 | throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining); 101 | } 102 | setParentEofDetect(true); 103 | return bytes; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Encodable.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | /** 7 | * Base class for objects which can be written directly to ASN.1 output streams. 8 | */ 9 | public abstract class ASN1Encodable 10 | implements DEREncodable 11 | { 12 | public static final String DER = "DER"; 13 | public static final String BER = "BER"; 14 | 15 | /** 16 | * Return the default BER or DER encoding for this object. 17 | * 18 | * @return BER/DER byte encoded object. 19 | * @throws IOException on encoding error. 20 | */ 21 | public byte[] getEncoded() 22 | throws IOException 23 | { 24 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 25 | ASN1OutputStream aOut = new ASN1OutputStream(bOut); 26 | 27 | aOut.writeObject(this); 28 | 29 | return bOut.toByteArray(); 30 | } 31 | 32 | /** 33 | * Return either the default for "BER" or a DER encoding if "DER" is specified. 34 | * 35 | * @param encoding name of encoding to use. 36 | * @return byte encoded object. 37 | * @throws IOException on encoding error. 38 | */ 39 | public byte[] getEncoded( 40 | String encoding) 41 | throws IOException 42 | { 43 | if (encoding.equals(DER)) 44 | { 45 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 46 | DEROutputStream dOut = new DEROutputStream(bOut); 47 | 48 | dOut.writeObject(this); 49 | 50 | return bOut.toByteArray(); 51 | } 52 | 53 | return this.getEncoded(); 54 | } 55 | 56 | /** 57 | * Return the DER encoding of the object, null if the DER encoding can not be made. 58 | * 59 | * @return a DER byte array, null otherwise. 60 | */ 61 | public byte[] getDEREncoded() 62 | { 63 | try 64 | { 65 | return this.getEncoded(DER); 66 | } 67 | catch (IOException e) 68 | { 69 | return null; 70 | } 71 | } 72 | 73 | public int hashCode() 74 | { 75 | return this.toASN1Object().hashCode(); 76 | } 77 | 78 | public boolean equals( 79 | Object o) 80 | { 81 | if (this == o) 82 | { 83 | return true; 84 | } 85 | 86 | if (!(o instanceof DEREncodable)) 87 | { 88 | return false; 89 | } 90 | 91 | DEREncodable other = (DEREncodable)o; 92 | 93 | return this.toASN1Object().equals(other.getDERObject()); 94 | } 95 | 96 | public DERObject getDERObject() 97 | { 98 | return this.toASN1Object(); 99 | } 100 | 101 | public abstract DERObject toASN1Object(); 102 | } 103 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'maven' 3 | apply plugin: 'signing' 4 | 5 | android { 6 | compileSdkVersion 23 7 | buildToolsVersion "23.0.1" 8 | 9 | defaultConfig { 10 | minSdkVersion 9 11 | targetSdkVersion 23 12 | versionCode 3 13 | versionName '2.1.0' 14 | } 15 | } 16 | 17 | /* maven deploy + signing */ 18 | task javadocs(type: Javadoc) { 19 | source = android.sourceSets.main.java.srcDirs 20 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) 21 | } 22 | 23 | task javadocsJar(type: Jar, dependsOn: javadocs) { 24 | classifier = 'javadoc' 25 | from javadocs.destinationDir 26 | } 27 | 28 | task sourcesJar(type: Jar) { 29 | classifier = 'sources' 30 | from android.sourceSets.main.java.srcDirs 31 | } 32 | 33 | task releaseJar(type: Jar, dependsOn: android.libraryVariants.release.javaCompile) { 34 | from projectDir.path + '/build/intermediates/classes/release/' 35 | } 36 | 37 | artifacts { 38 | archives releaseJar 39 | archives sourcesJar 40 | archives javadocsJar 41 | } 42 | 43 | signing { 44 | sign configurations.archives 45 | } 46 | 47 | def sonatypeUsername = System.properties['sonatypeUsername'] ?: '' 48 | def sonatypePassword = System.properties['sonatypePassword'] ?: '' 49 | 50 | uploadArchives { 51 | repositories { 52 | mavenDeployer { 53 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } 54 | 55 | repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') { 56 | authentication(userName: sonatypeUsername, password: sonatypePassword) 57 | } 58 | 59 | pom.setArtifactId 'encryption' 60 | 61 | pom.project { 62 | name 'encryption' 63 | groupId = 'com.braintreepayments' 64 | version = "${android.defaultConfig.versionName}" 65 | packaging 'jar' 66 | description 'Client side encryption for Braintree integrations on Android.' 67 | url 'https://github.com/braintree/braintree_android_encryption' 68 | 69 | scm { 70 | url 'scm:git@github.com:braintree/braintree_android_encryption.git' 71 | connection 'scm:git@github.com:braintree/braintree_android_encryption.git' 72 | developerConnection 'scm:git@github.com:braintree/braintree_android_encryption.git' 73 | } 74 | 75 | developers { 76 | developer { 77 | id 'devs' 78 | name 'Braintree Payments' 79 | } 80 | } 81 | 82 | licenses { 83 | license { 84 | name 'MIT' 85 | url 'http://opensource.org/licenses/MIT' 86 | distribution 'repo' 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1.x509; 2 | 3 | import java.math.BigInteger; 4 | import java.util.Enumeration; 5 | 6 | import com.braintree.org.bouncycastle.asn1.ASN1Encodable; 7 | import com.braintree.org.bouncycastle.asn1.ASN1EncodableVector; 8 | import com.braintree.org.bouncycastle.asn1.ASN1Sequence; 9 | import com.braintree.org.bouncycastle.asn1.ASN1TaggedObject; 10 | import com.braintree.org.bouncycastle.asn1.DERInteger; 11 | import com.braintree.org.bouncycastle.asn1.DERObject; 12 | import com.braintree.org.bouncycastle.asn1.DERSequence; 13 | 14 | public class RSAPublicKeyStructure 15 | extends ASN1Encodable 16 | { 17 | private BigInteger modulus; 18 | private BigInteger publicExponent; 19 | 20 | public static RSAPublicKeyStructure getInstance( 21 | ASN1TaggedObject obj, 22 | boolean explicit) 23 | { 24 | return getInstance(ASN1Sequence.getInstance(obj, explicit)); 25 | } 26 | 27 | public static RSAPublicKeyStructure getInstance( 28 | Object obj) 29 | { 30 | if(obj == null || obj instanceof RSAPublicKeyStructure) 31 | { 32 | return (RSAPublicKeyStructure)obj; 33 | } 34 | 35 | if(obj instanceof ASN1Sequence) 36 | { 37 | return new RSAPublicKeyStructure((ASN1Sequence)obj); 38 | } 39 | 40 | throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName()); 41 | } 42 | 43 | public RSAPublicKeyStructure( 44 | BigInteger modulus, 45 | BigInteger publicExponent) 46 | { 47 | this.modulus = modulus; 48 | this.publicExponent = publicExponent; 49 | } 50 | 51 | public RSAPublicKeyStructure( 52 | ASN1Sequence seq) 53 | { 54 | if (seq.size() != 2) 55 | { 56 | throw new IllegalArgumentException("Bad sequence size: " 57 | + seq.size()); 58 | } 59 | 60 | Enumeration e = seq.getObjects(); 61 | 62 | modulus = DERInteger.getInstance(e.nextElement()).getPositiveValue(); 63 | publicExponent = DERInteger.getInstance(e.nextElement()).getPositiveValue(); 64 | } 65 | 66 | public BigInteger getModulus() 67 | { 68 | return modulus; 69 | } 70 | 71 | public BigInteger getPublicExponent() 72 | { 73 | return publicExponent; 74 | } 75 | 76 | /** 77 | * This outputs the key in PKCS1v2 format. 78 | *

79 |      *      RSAPublicKey ::= SEQUENCE {
80 |      *                          modulus INTEGER, -- n
81 |      *                          publicExponent INTEGER, -- e
82 |      *                      }
83 |      * 
84 | *

85 | */ 86 | public DERObject toASN1Object() 87 | { 88 | ASN1EncodableVector v = new ASN1EncodableVector(); 89 | 90 | v.add(new DERInteger(getModulus())); 91 | v.add(new DERInteger(getPublicExponent())); 92 | 93 | return new DERSequence(v); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ConstructedOctetStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.InputStream; 4 | import java.io.IOException; 5 | 6 | class ConstructedOctetStream 7 | extends InputStream 8 | { 9 | private final ASN1StreamParser _parser; 10 | 11 | private boolean _first = true; 12 | private InputStream _currentStream; 13 | 14 | ConstructedOctetStream( 15 | ASN1StreamParser parser) 16 | { 17 | _parser = parser; 18 | } 19 | 20 | public int read(byte[] b, int off, int len) throws IOException 21 | { 22 | if (_currentStream == null) 23 | { 24 | if (!_first) 25 | { 26 | return -1; 27 | } 28 | 29 | ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); 30 | 31 | if (s == null) 32 | { 33 | return -1; 34 | } 35 | 36 | _first = false; 37 | _currentStream = s.getOctetStream(); 38 | } 39 | 40 | int totalRead = 0; 41 | 42 | for (;;) 43 | { 44 | int numRead = _currentStream.read(b, off + totalRead, len - totalRead); 45 | 46 | if (numRead >= 0) 47 | { 48 | totalRead += numRead; 49 | 50 | if (totalRead == len) 51 | { 52 | return totalRead; 53 | } 54 | } 55 | else 56 | { 57 | ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject(); 58 | 59 | if (aos == null) 60 | { 61 | _currentStream = null; 62 | return totalRead < 1 ? -1 : totalRead; 63 | } 64 | 65 | _currentStream = aos.getOctetStream(); 66 | } 67 | } 68 | } 69 | 70 | public int read() 71 | throws IOException 72 | { 73 | if (_currentStream == null) 74 | { 75 | if (!_first) 76 | { 77 | return -1; 78 | } 79 | 80 | ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); 81 | 82 | if (s == null) 83 | { 84 | return -1; 85 | } 86 | 87 | _first = false; 88 | _currentStream = s.getOctetStream(); 89 | } 90 | 91 | for (;;) 92 | { 93 | int b = _currentStream.read(); 94 | 95 | if (b >= 0) 96 | { 97 | return b; 98 | } 99 | 100 | ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); 101 | 102 | if (s == null) 103 | { 104 | _currentStream = null; 105 | return -1; 106 | } 107 | 108 | _currentStream = s.getOctetStream(); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERUTF8String.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | import com.braintree.org.bouncycastle.util.Strings; 6 | 7 | /** 8 | * DER UTF8String object. 9 | */ 10 | public class DERUTF8String 11 | extends ASN1Object 12 | implements DERString 13 | { 14 | String string; 15 | 16 | /** 17 | * return an UTF8 string from the passed in object. 18 | * 19 | * @exception IllegalArgumentException 20 | * if the object cannot be converted. 21 | */ 22 | public static DERUTF8String getInstance(Object obj) 23 | { 24 | if (obj == null || obj instanceof DERUTF8String) 25 | { 26 | return (DERUTF8String)obj; 27 | } 28 | 29 | throw new IllegalArgumentException("illegal object in getInstance: " 30 | + obj.getClass().getName()); 31 | } 32 | 33 | /** 34 | * return an UTF8 String from a tagged object. 35 | * 36 | * @param obj 37 | * the tagged object holding the object we want 38 | * @param explicit 39 | * true if the object is meant to be explicitly tagged false 40 | * otherwise. 41 | * @exception IllegalArgumentException 42 | * if the tagged object cannot be converted. 43 | */ 44 | public static DERUTF8String getInstance( 45 | ASN1TaggedObject obj, 46 | boolean explicit) 47 | { 48 | DERObject o = obj.getObject(); 49 | 50 | if (explicit || o instanceof DERUTF8String) 51 | { 52 | return getInstance(o); 53 | } 54 | else 55 | { 56 | return new DERUTF8String(ASN1OctetString.getInstance(o).getOctets()); 57 | } 58 | } 59 | 60 | /** 61 | * basic constructor - byte encoded string. 62 | */ 63 | public DERUTF8String(byte[] string) 64 | { 65 | try 66 | { 67 | this.string = Strings.fromUTF8ByteArray(string); 68 | } 69 | catch (ArrayIndexOutOfBoundsException e) 70 | { 71 | throw new IllegalArgumentException("UTF8 encoding invalid"); 72 | } 73 | } 74 | 75 | /** 76 | * basic constructor 77 | */ 78 | public DERUTF8String(String string) 79 | { 80 | this.string = string; 81 | } 82 | 83 | public String getString() 84 | { 85 | return string; 86 | } 87 | 88 | public String toString() 89 | { 90 | return string; 91 | } 92 | 93 | public int hashCode() 94 | { 95 | return this.getString().hashCode(); 96 | } 97 | 98 | boolean asn1Equals(DERObject o) 99 | { 100 | if (!(o instanceof DERUTF8String)) 101 | { 102 | return false; 103 | } 104 | 105 | DERUTF8String s = (DERUTF8String)o; 106 | 107 | return this.getString().equals(s.getString()); 108 | } 109 | 110 | void encode(DEROutputStream out) 111 | throws IOException 112 | { 113 | out.writeEncoded(UTF8_STRING, Strings.toUTF8ByteArray(string)); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERBoolean.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | public class DERBoolean 6 | extends ASN1Object 7 | { 8 | byte value; 9 | 10 | public static final DERBoolean FALSE = new DERBoolean(false); 11 | public static final DERBoolean TRUE = new DERBoolean(true); 12 | 13 | /** 14 | * return a boolean from the passed in object. 15 | * 16 | * @exception IllegalArgumentException if the object cannot be converted. 17 | */ 18 | public static DERBoolean getInstance( 19 | Object obj) 20 | { 21 | if (obj == null || obj instanceof DERBoolean) 22 | { 23 | return (DERBoolean)obj; 24 | } 25 | 26 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 27 | } 28 | 29 | /** 30 | * return a DERBoolean from the passed in boolean. 31 | */ 32 | public static DERBoolean getInstance( 33 | boolean value) 34 | { 35 | return (value ? TRUE : FALSE); 36 | } 37 | 38 | /** 39 | * return a Boolean from a tagged object. 40 | * 41 | * @param obj the tagged object holding the object we want 42 | * @param explicit true if the object is meant to be explicitly 43 | * tagged false otherwise. 44 | * @exception IllegalArgumentException if the tagged object cannot 45 | * be converted. 46 | */ 47 | public static DERBoolean getInstance( 48 | ASN1TaggedObject obj, 49 | boolean explicit) 50 | { 51 | DERObject o = obj.getObject(); 52 | 53 | if (explicit || o instanceof DERBoolean) 54 | { 55 | return getInstance(o); 56 | } 57 | else 58 | { 59 | return new DERBoolean(((ASN1OctetString)o).getOctets()); 60 | } 61 | } 62 | 63 | public DERBoolean( 64 | byte[] value) 65 | { 66 | if (value.length != 1) 67 | { 68 | throw new IllegalArgumentException("byte value should have 1 byte in it"); 69 | } 70 | 71 | this.value = value[0]; 72 | } 73 | 74 | public DERBoolean( 75 | boolean value) 76 | { 77 | this.value = (value) ? (byte)0xff : (byte)0; 78 | } 79 | 80 | public boolean isTrue() 81 | { 82 | return (value != 0); 83 | } 84 | 85 | void encode( 86 | DEROutputStream out) 87 | throws IOException 88 | { 89 | byte[] bytes = new byte[1]; 90 | 91 | bytes[0] = value; 92 | 93 | out.writeEncoded(BOOLEAN, bytes); 94 | } 95 | 96 | protected boolean asn1Equals( 97 | DERObject o) 98 | { 99 | if ((o == null) || !(o instanceof DERBoolean)) 100 | { 101 | return false; 102 | } 103 | 104 | return (value == ((DERBoolean)o).value); 105 | } 106 | 107 | public int hashCode() 108 | { 109 | return value; 110 | } 111 | 112 | 113 | public String toString() 114 | { 115 | return (value != 0) ? "TRUE" : "FALSE"; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERInteger.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.math.BigInteger; 5 | 6 | import com.braintree.org.bouncycastle.util.Arrays; 7 | 8 | public class DERInteger 9 | extends ASN1Object 10 | { 11 | byte[] bytes; 12 | 13 | /** 14 | * return an integer from the passed in object 15 | * 16 | * @exception IllegalArgumentException if the object cannot be converted. 17 | */ 18 | public static DERInteger getInstance( 19 | Object obj) 20 | { 21 | if (obj == null || obj instanceof DERInteger) 22 | { 23 | return (DERInteger)obj; 24 | } 25 | 26 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 27 | } 28 | 29 | /** 30 | * return an Integer from a tagged object. 31 | * 32 | * @param obj the tagged object holding the object we want 33 | * @param explicit true if the object is meant to be explicitly 34 | * tagged false otherwise. 35 | * @exception IllegalArgumentException if the tagged object cannot 36 | * be converted. 37 | */ 38 | public static DERInteger getInstance( 39 | ASN1TaggedObject obj, 40 | boolean explicit) 41 | { 42 | DERObject o = obj.getObject(); 43 | 44 | if (explicit || o instanceof DERInteger) 45 | { 46 | return getInstance(o); 47 | } 48 | else 49 | { 50 | return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); 51 | } 52 | } 53 | 54 | public DERInteger( 55 | int value) 56 | { 57 | bytes = BigInteger.valueOf(value).toByteArray(); 58 | } 59 | 60 | public DERInteger( 61 | BigInteger value) 62 | { 63 | bytes = value.toByteArray(); 64 | } 65 | 66 | public DERInteger( 67 | byte[] bytes) 68 | { 69 | this.bytes = bytes; 70 | } 71 | 72 | public BigInteger getValue() 73 | { 74 | return new BigInteger(bytes); 75 | } 76 | 77 | /** 78 | * in some cases positive values get crammed into a space, 79 | * that's not quite big enough... 80 | */ 81 | public BigInteger getPositiveValue() 82 | { 83 | return new BigInteger(1, bytes); 84 | } 85 | 86 | void encode( 87 | DEROutputStream out) 88 | throws IOException 89 | { 90 | out.writeEncoded(INTEGER, bytes); 91 | } 92 | 93 | public int hashCode() 94 | { 95 | int value = 0; 96 | 97 | for (int i = 0; i != bytes.length; i++) 98 | { 99 | value ^= (bytes[i] & 0xff) << (i % 4); 100 | } 101 | 102 | return value; 103 | } 104 | 105 | boolean asn1Equals( 106 | DERObject o) 107 | { 108 | if (!(o instanceof DERInteger)) 109 | { 110 | return false; 111 | } 112 | 113 | DERInteger other = (DERInteger)o; 114 | 115 | return Arrays.areEqual(bytes, other.bytes); 116 | } 117 | 118 | public String toString() 119 | { 120 | return getValue().toString(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERT61String.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER T61String (also the teletex string) 7 | */ 8 | public class DERT61String 9 | extends ASN1Object 10 | implements DERString 11 | { 12 | String string; 13 | 14 | /** 15 | * return a T61 string from the passed in object. 16 | * 17 | * @exception IllegalArgumentException if the object cannot be converted. 18 | */ 19 | public static DERT61String getInstance( 20 | Object obj) 21 | { 22 | if (obj == null || obj instanceof DERT61String) 23 | { 24 | return (DERT61String)obj; 25 | } 26 | 27 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 28 | } 29 | 30 | /** 31 | * return an T61 String from a tagged object. 32 | * 33 | * @param obj the tagged object holding the object we want 34 | * @param explicit true if the object is meant to be explicitly 35 | * tagged false otherwise. 36 | * @exception IllegalArgumentException if the tagged object cannot 37 | * be converted. 38 | */ 39 | public static DERT61String getInstance( 40 | ASN1TaggedObject obj, 41 | boolean explicit) 42 | { 43 | DERObject o = obj.getObject(); 44 | 45 | if (explicit) 46 | { 47 | return getInstance(o); 48 | } 49 | else 50 | { 51 | return new DERT61String(ASN1OctetString.getInstance(o).getOctets()); 52 | } 53 | } 54 | 55 | /** 56 | * basic constructor - with bytes. 57 | */ 58 | public DERT61String( 59 | byte[] string) 60 | { 61 | char[] cs = new char[string.length]; 62 | 63 | for (int i = 0; i != cs.length; i++) 64 | { 65 | cs[i] = (char)(string[i] & 0xff); 66 | } 67 | 68 | this.string = new String(cs); 69 | } 70 | 71 | /** 72 | * basic constructor - with string. 73 | */ 74 | public DERT61String( 75 | String string) 76 | { 77 | this.string = string; 78 | } 79 | 80 | public String getString() 81 | { 82 | return string; 83 | } 84 | 85 | public String toString() 86 | { 87 | return string; 88 | } 89 | 90 | void encode( 91 | DEROutputStream out) 92 | throws IOException 93 | { 94 | out.writeEncoded(T61_STRING, this.getOctets()); 95 | } 96 | 97 | public byte[] getOctets() 98 | { 99 | char[] cs = string.toCharArray(); 100 | byte[] bs = new byte[cs.length]; 101 | 102 | for (int i = 0; i != cs.length; i++) 103 | { 104 | bs[i] = (byte)cs[i]; 105 | } 106 | 107 | return bs; 108 | } 109 | 110 | boolean asn1Equals( 111 | DERObject o) 112 | { 113 | if (!(o instanceof DERT61String)) 114 | { 115 | return false; 116 | } 117 | 118 | return this.getString().equals(((DERT61String)o).getString()); 119 | } 120 | 121 | public int hashCode() 122 | { 123 | return this.getString().hashCode(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/androidTest/java/com/braintreegateway/encryption/util/AesDecrypter.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption.util; 2 | 3 | import com.braintree.org.bouncycastle.util.encoders.Base64; 4 | 5 | import java.security.InvalidAlgorithmParameterException; 6 | import java.security.InvalidKeyException; 7 | import java.security.NoSuchAlgorithmException; 8 | 9 | import javax.crypto.BadPaddingException; 10 | import javax.crypto.Cipher; 11 | import javax.crypto.IllegalBlockSizeException; 12 | import javax.crypto.NoSuchPaddingException; 13 | import javax.crypto.spec.IvParameterSpec; 14 | import javax.crypto.spec.SecretKeySpec; 15 | 16 | public final class AesDecrypter { 17 | private static int IV_LENGTH = 16; 18 | 19 | public static byte[] decrypt(String data, byte[] aesKey) throws InvalidKeyException, 20 | IllegalBlockSizeException, 21 | BadPaddingException, 22 | InvalidAlgorithmParameterException, 23 | NoSuchAlgorithmException, 24 | NoSuchPaddingException { 25 | byte[] decodedData = Base64.decode(data); 26 | byte[] derivedIV = getIV(decodedData); 27 | return decrypt(data, aesKey, derivedIV); 28 | } 29 | 30 | public static byte[] decrypt(String data, byte[] aesKey, byte[] suppliedIV) throws InvalidKeyException, 31 | IllegalBlockSizeException, 32 | BadPaddingException, 33 | InvalidAlgorithmParameterException, 34 | NoSuchAlgorithmException, 35 | NoSuchPaddingException { 36 | byte[] keyBytes = Base64.decode(aesKey); 37 | SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 38 | Cipher cipher = aesCipher(); 39 | byte[] decodedData = Base64.decode(data); 40 | byte[] encryptedData = getEncryptedData(decodedData); 41 | IvParameterSpec ivParamSpec = new IvParameterSpec(suppliedIV); 42 | cipher.init(Cipher.DECRYPT_MODE, key, ivParamSpec); 43 | return cipher.doFinal(encryptedData); 44 | } 45 | 46 | private static byte[] getIV(byte[] data) { 47 | byte[] buffer = new byte[IV_LENGTH]; 48 | for (int i = 0; i < IV_LENGTH; i++) { 49 | buffer[i] = data[i]; 50 | } 51 | return buffer; 52 | } 53 | 54 | private static byte[] getEncryptedData(byte[] data) { 55 | byte[] buffer = new byte[data.length - IV_LENGTH]; 56 | int bufferIndex = 0; 57 | for (int i = IV_LENGTH; i < data.length; i++) { 58 | buffer[bufferIndex] = data[i]; 59 | bufferIndex++; 60 | } 61 | return buffer; 62 | } 63 | 64 | private static Cipher aesCipher() throws NoSuchAlgorithmException, NoSuchPaddingException { 65 | return Cipher.getInstance("AES/CBC/PKCS5Padding"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERBMPString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER BMPString object. 7 | */ 8 | public class DERBMPString 9 | extends ASN1Object 10 | implements DERString 11 | { 12 | String string; 13 | 14 | /** 15 | * return a BMP String from the given object. 16 | * 17 | * @param obj the object we want converted. 18 | * @exception IllegalArgumentException if the object cannot be converted. 19 | */ 20 | public static DERBMPString getInstance( 21 | Object obj) 22 | { 23 | if (obj == null || obj instanceof DERBMPString) 24 | { 25 | return (DERBMPString)obj; 26 | } 27 | 28 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 29 | } 30 | 31 | /** 32 | * return a BMP String from a tagged object. 33 | * 34 | * @param obj the tagged object holding the object we want 35 | * @param explicit true if the object is meant to be explicitly 36 | * tagged false otherwise. 37 | * @exception IllegalArgumentException if the tagged object cannot 38 | * be converted. 39 | */ 40 | public static DERBMPString getInstance( 41 | ASN1TaggedObject obj, 42 | boolean explicit) 43 | { 44 | DERObject o = obj.getObject(); 45 | 46 | if (explicit || o instanceof DERBMPString) 47 | { 48 | return getInstance(o); 49 | } 50 | else 51 | { 52 | return new DERBMPString(ASN1OctetString.getInstance(o).getOctets()); 53 | } 54 | } 55 | 56 | 57 | /** 58 | * basic constructor - byte encoded string. 59 | */ 60 | public DERBMPString( 61 | byte[] string) 62 | { 63 | char[] cs = new char[string.length / 2]; 64 | 65 | for (int i = 0; i != cs.length; i++) 66 | { 67 | cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff)); 68 | } 69 | 70 | this.string = new String(cs); 71 | } 72 | 73 | /** 74 | * basic constructor 75 | */ 76 | public DERBMPString( 77 | String string) 78 | { 79 | this.string = string; 80 | } 81 | 82 | public String getString() 83 | { 84 | return string; 85 | } 86 | 87 | public String toString() 88 | { 89 | return string; 90 | } 91 | 92 | public int hashCode() 93 | { 94 | return this.getString().hashCode(); 95 | } 96 | 97 | protected boolean asn1Equals( 98 | DERObject o) 99 | { 100 | if (!(o instanceof DERBMPString)) 101 | { 102 | return false; 103 | } 104 | 105 | DERBMPString s = (DERBMPString)o; 106 | 107 | return this.getString().equals(s.getString()); 108 | } 109 | 110 | void encode( 111 | DEROutputStream out) 112 | throws IOException 113 | { 114 | char[] c = string.toCharArray(); 115 | byte[] b = new byte[c.length * 2]; 116 | 117 | for (int i = 0; i != c.length; i++) 118 | { 119 | b[2 * i] = (byte)(c[i] >> 8); 120 | b[2 * i + 1] = (byte)c[i]; 121 | } 122 | 123 | out.writeEncoded(BMP_STRING, b); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERVisibleString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER VisibleString object. 7 | */ 8 | public class DERVisibleString 9 | extends ASN1Object 10 | implements DERString 11 | { 12 | String string; 13 | 14 | /** 15 | * return a Visible String from the passed in object. 16 | * 17 | * @exception IllegalArgumentException if the object cannot be converted. 18 | */ 19 | public static DERVisibleString getInstance( 20 | Object obj) 21 | { 22 | if (obj == null || obj instanceof DERVisibleString) 23 | { 24 | return (DERVisibleString)obj; 25 | } 26 | 27 | if (obj instanceof ASN1OctetString) 28 | { 29 | return new DERVisibleString(((ASN1OctetString)obj).getOctets()); 30 | } 31 | 32 | if (obj instanceof ASN1TaggedObject) 33 | { 34 | return getInstance(((ASN1TaggedObject)obj).getObject()); 35 | } 36 | 37 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 38 | } 39 | 40 | /** 41 | * return a Visible String from a tagged object. 42 | * 43 | * @param obj the tagged object holding the object we want 44 | * @param explicit true if the object is meant to be explicitly 45 | * tagged false otherwise. 46 | * @exception IllegalArgumentException if the tagged object cannot 47 | * be converted. 48 | */ 49 | public static DERVisibleString getInstance( 50 | ASN1TaggedObject obj, 51 | boolean explicit) 52 | { 53 | return getInstance(obj.getObject()); 54 | } 55 | 56 | /** 57 | * basic constructor - byte encoded string. 58 | */ 59 | public DERVisibleString( 60 | byte[] string) 61 | { 62 | char[] cs = new char[string.length]; 63 | 64 | for (int i = 0; i != cs.length; i++) 65 | { 66 | cs[i] = (char)(string[i] & 0xff); 67 | } 68 | 69 | this.string = new String(cs); 70 | } 71 | 72 | /** 73 | * basic constructor 74 | */ 75 | public DERVisibleString( 76 | String string) 77 | { 78 | this.string = string; 79 | } 80 | 81 | public String getString() 82 | { 83 | return string; 84 | } 85 | 86 | public String toString() 87 | { 88 | return string; 89 | } 90 | 91 | public byte[] getOctets() 92 | { 93 | char[] cs = string.toCharArray(); 94 | byte[] bs = new byte[cs.length]; 95 | 96 | for (int i = 0; i != cs.length; i++) 97 | { 98 | bs[i] = (byte)cs[i]; 99 | } 100 | 101 | return bs; 102 | } 103 | 104 | void encode( 105 | DEROutputStream out) 106 | throws IOException 107 | { 108 | out.writeEncoded(VISIBLE_STRING, this.getOctets()); 109 | } 110 | 111 | boolean asn1Equals( 112 | DERObject o) 113 | { 114 | if (!(o instanceof DERVisibleString)) 115 | { 116 | return false; 117 | } 118 | 119 | return this.getString().equals(((DERVisibleString)o).getString()); 120 | } 121 | 122 | public int hashCode() 123 | { 124 | return this.getString().hashCode(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DEROutputStream.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.FilterOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | 7 | public class DEROutputStream 8 | extends FilterOutputStream implements DERTags 9 | { 10 | public DEROutputStream( 11 | OutputStream os) 12 | { 13 | super(os); 14 | } 15 | 16 | private void writeLength( 17 | int length) 18 | throws IOException 19 | { 20 | if (length > 127) 21 | { 22 | int size = 1; 23 | int val = length; 24 | 25 | while ((val >>>= 8) != 0) 26 | { 27 | size++; 28 | } 29 | 30 | write((byte)(size | 0x80)); 31 | 32 | for (int i = (size - 1) * 8; i >= 0; i -= 8) 33 | { 34 | write((byte)(length >> i)); 35 | } 36 | } 37 | else 38 | { 39 | write((byte)length); 40 | } 41 | } 42 | 43 | void writeEncoded( 44 | int tag, 45 | byte[] bytes) 46 | throws IOException 47 | { 48 | write(tag); 49 | writeLength(bytes.length); 50 | write(bytes); 51 | } 52 | 53 | void writeTag(int flags, int tagNo) 54 | throws IOException 55 | { 56 | if (tagNo < 31) 57 | { 58 | write(flags | tagNo); 59 | } 60 | else 61 | { 62 | write(flags | 0x1f); 63 | if (tagNo < 128) 64 | { 65 | write(tagNo); 66 | } 67 | else 68 | { 69 | byte[] stack = new byte[5]; 70 | int pos = stack.length; 71 | 72 | stack[--pos] = (byte)(tagNo & 0x7F); 73 | 74 | do 75 | { 76 | tagNo >>= 7; 77 | stack[--pos] = (byte)(tagNo & 0x7F | 0x80); 78 | } 79 | while (tagNo > 127); 80 | 81 | write(stack, pos, stack.length - pos); 82 | } 83 | } 84 | } 85 | 86 | void writeEncoded(int flags, int tagNo, byte[] bytes) 87 | throws IOException 88 | { 89 | writeTag(flags, tagNo); 90 | writeLength(bytes.length); 91 | write(bytes); 92 | } 93 | 94 | protected void writeNull() 95 | throws IOException 96 | { 97 | write(NULL); 98 | write(0x00); 99 | } 100 | 101 | public void write(byte[] buf) 102 | throws IOException 103 | { 104 | out.write(buf, 0, buf.length); 105 | } 106 | 107 | public void write(byte[] buf, int offSet, int len) 108 | throws IOException 109 | { 110 | out.write(buf, offSet, len); 111 | } 112 | 113 | public void writeObject( 114 | Object obj) 115 | throws IOException 116 | { 117 | if (obj == null) 118 | { 119 | writeNull(); 120 | } 121 | else if (obj instanceof DERObject) 122 | { 123 | ((DERObject)obj).encode(this); 124 | } 125 | else if (obj instanceof DEREncodable) 126 | { 127 | ((DEREncodable)obj).getDERObject().encode(this); 128 | } 129 | else 130 | { 131 | throw new IOException("object not DEREncodable"); 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintreegateway/encryption/Rsa.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption; 2 | 3 | import java.io.IOException; 4 | import java.security.InvalidKeyException; 5 | import java.security.KeyFactory; 6 | import java.security.NoSuchAlgorithmException; 7 | import java.security.PublicKey; 8 | import java.security.spec.InvalidKeySpecException; 9 | import java.security.spec.RSAPublicKeySpec; 10 | 11 | import javax.crypto.BadPaddingException; 12 | import javax.crypto.Cipher; 13 | import javax.crypto.IllegalBlockSizeException; 14 | import javax.crypto.NoSuchPaddingException; 15 | 16 | import com.braintree.org.bouncycastle.asn1.ASN1InputStream; 17 | import com.braintree.org.bouncycastle.asn1.DERObject; 18 | import com.braintree.org.bouncycastle.asn1.x509.RSAPublicKeyStructure; 19 | import com.braintree.org.bouncycastle.util.encoders.Base64; 20 | 21 | public final class Rsa { 22 | private static final String ALGORITHM = "RSA"; 23 | private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; 24 | 25 | public static String encrypt(byte[] data, String publicKeyString) throws BraintreeEncryptionException { 26 | Cipher rsa; 27 | try { 28 | rsa = Cipher.getInstance(TRANSFORMATION); 29 | PublicKey publicKey = publicKey(publicKeyString); 30 | rsa.init(Cipher.ENCRYPT_MODE, publicKey); 31 | byte[] encodedData = Base64.encode(data); 32 | byte[] encryptedData = rsa.doFinal(encodedData); 33 | return new String(Base64.encode(encryptedData)); 34 | } catch (NoSuchAlgorithmException e) { 35 | throw new BraintreeEncryptionException("No Such Algorithm: " + e.getMessage()); 36 | } catch (NoSuchPaddingException e) { 37 | throw new BraintreeEncryptionException("No Such Padding: " + e.getMessage()); 38 | } catch (InvalidKeyException e) { 39 | throw new BraintreeEncryptionException("Invalid Key: " + e.getMessage()); 40 | } catch (IllegalBlockSizeException e) { 41 | throw new BraintreeEncryptionException("Illegal Block Size: " + e.getMessage()); 42 | } catch (BadPaddingException e) { 43 | throw new BraintreeEncryptionException("Bad Padding: " + e.getMessage()); 44 | } 45 | } 46 | 47 | private static PublicKey publicKey(String publicKeyString) throws BraintreeEncryptionException { 48 | ASN1InputStream in = null; 49 | try { 50 | byte[] decodedPublicKey = Base64.decode(publicKeyString); 51 | in = new ASN1InputStream(decodedPublicKey); 52 | DERObject obj = in.readObject(); 53 | RSAPublicKeyStructure keyStruct = RSAPublicKeyStructure.getInstance(obj); 54 | RSAPublicKeySpec keySpec = new RSAPublicKeySpec(keyStruct.getModulus(), keyStruct.getPublicExponent()); 55 | KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); 56 | return keyFactory.generatePublic(keySpec); 57 | } catch (NoSuchAlgorithmException e) { 58 | throw new BraintreeEncryptionException("No Such Algorithm: " + e.getMessage()); 59 | } catch (InvalidKeySpecException e) { 60 | throw new BraintreeEncryptionException("Invalid Key Spec: " + e.getMessage()); 61 | } catch (IOException e) { 62 | throw new BraintreeEncryptionException("IO Exception: " + e.getMessage()); 63 | } finally { 64 | try { 65 | in.close(); 66 | } catch (IOException e) { 67 | throw new BraintreeEncryptionException("IO Exception: " + e.getMessage()); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERTaggedObject.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.util.Enumeration; 5 | 6 | /** 7 | * BER TaggedObject - in ASN.1 notation this is any object preceded by 8 | * a [n] where n is some number - these are assumed to follow the construction 9 | * rules (as with sequences). 10 | */ 11 | public class BERTaggedObject 12 | extends DERTaggedObject 13 | { 14 | /** 15 | * @param tagNo the tag number for this object. 16 | * @param obj the tagged object. 17 | */ 18 | public BERTaggedObject( 19 | int tagNo, 20 | DEREncodable obj) 21 | { 22 | super(tagNo, obj); 23 | } 24 | 25 | /** 26 | * @param explicit true if an explicitly tagged object. 27 | * @param tagNo the tag number for this object. 28 | * @param obj the tagged object. 29 | */ 30 | public BERTaggedObject( 31 | boolean explicit, 32 | int tagNo, 33 | DEREncodable obj) 34 | { 35 | super(explicit, tagNo, obj); 36 | } 37 | 38 | /** 39 | * create an implicitly tagged object that contains a zero 40 | * length sequence. 41 | */ 42 | public BERTaggedObject( 43 | int tagNo) 44 | { 45 | super(false, tagNo, new BERSequence()); 46 | } 47 | 48 | void encode( 49 | DEROutputStream out) 50 | throws IOException 51 | { 52 | if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) 53 | { 54 | out.writeTag(CONSTRUCTED | TAGGED, tagNo); 55 | out.write(0x80); 56 | 57 | if (!empty) 58 | { 59 | if (!explicit) 60 | { 61 | Enumeration e; 62 | if (obj instanceof ASN1OctetString) 63 | { 64 | if (obj instanceof BERConstructedOctetString) 65 | { 66 | e = ((BERConstructedOctetString)obj).getObjects(); 67 | } 68 | else 69 | { 70 | ASN1OctetString octs = (ASN1OctetString)obj; 71 | BERConstructedOctetString berO = new BERConstructedOctetString(octs.getOctets()); 72 | e = berO.getObjects(); 73 | } 74 | } 75 | else if (obj instanceof ASN1Sequence) 76 | { 77 | e = ((ASN1Sequence)obj).getObjects(); 78 | } 79 | else if (obj instanceof ASN1Set) 80 | { 81 | e = ((ASN1Set)obj).getObjects(); 82 | } 83 | else 84 | { 85 | throw new RuntimeException("not implemented: " + obj.getClass().getName()); 86 | } 87 | 88 | while (e.hasMoreElements()) 89 | { 90 | out.writeObject(e.nextElement()); 91 | } 92 | } 93 | else 94 | { 95 | out.writeObject(obj); 96 | } 97 | } 98 | 99 | out.write(0x00); 100 | out.write(0x00); 101 | } 102 | else 103 | { 104 | super.encode(out); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERUniversalString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | /** 7 | * DER UniversalString object. 8 | */ 9 | public class DERUniversalString 10 | extends ASN1Object 11 | implements DERString 12 | { 13 | private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 14 | private byte[] string; 15 | 16 | /** 17 | * return a Universal String from the passed in object. 18 | * 19 | * @exception IllegalArgumentException if the object cannot be converted. 20 | */ 21 | public static DERUniversalString getInstance( 22 | Object obj) 23 | { 24 | if (obj == null || obj instanceof DERUniversalString) 25 | { 26 | return (DERUniversalString)obj; 27 | } 28 | 29 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 30 | } 31 | 32 | /** 33 | * return a Universal String from a tagged object. 34 | * 35 | * @param obj the tagged object holding the object we want 36 | * @param explicit true if the object is meant to be explicitly 37 | * tagged false otherwise. 38 | * @exception IllegalArgumentException if the tagged object cannot 39 | * be converted. 40 | */ 41 | public static DERUniversalString getInstance( 42 | ASN1TaggedObject obj, 43 | boolean explicit) 44 | { 45 | DERObject o = obj.getObject(); 46 | 47 | if (explicit || o instanceof DERUniversalString) 48 | { 49 | return getInstance(o); 50 | } 51 | else 52 | { 53 | return new DERUniversalString(((ASN1OctetString)o).getOctets()); 54 | } 55 | } 56 | 57 | /** 58 | * basic constructor - byte encoded string. 59 | */ 60 | public DERUniversalString( 61 | byte[] string) 62 | { 63 | this.string = string; 64 | } 65 | 66 | public String getString() 67 | { 68 | StringBuffer buf = new StringBuffer("#"); 69 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 70 | ASN1OutputStream aOut = new ASN1OutputStream(bOut); 71 | 72 | try 73 | { 74 | aOut.writeObject(this); 75 | } 76 | catch (IOException e) 77 | { 78 | throw new RuntimeException("internal error encoding BitString"); 79 | } 80 | 81 | byte[] string = bOut.toByteArray(); 82 | 83 | for (int i = 0; i != string.length; i++) 84 | { 85 | buf.append(table[(string[i] >>> 4) & 0xf]); 86 | buf.append(table[string[i] & 0xf]); 87 | } 88 | 89 | return buf.toString(); 90 | } 91 | 92 | public String toString() 93 | { 94 | return getString(); 95 | } 96 | 97 | public byte[] getOctets() 98 | { 99 | return string; 100 | } 101 | 102 | void encode( 103 | DEROutputStream out) 104 | throws IOException 105 | { 106 | out.writeEncoded(UNIVERSAL_STRING, this.getOctets()); 107 | } 108 | 109 | boolean asn1Equals( 110 | DERObject o) 111 | { 112 | if (!(o instanceof DERUniversalString)) 113 | { 114 | return false; 115 | } 116 | 117 | return this.getString().equals(((DERUniversalString)o).getString()); 118 | } 119 | 120 | public int hashCode() 121 | { 122 | return this.getString().hashCode(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/encoders/Base64.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util.encoders; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | 7 | public class Base64 8 | { 9 | private static final Encoder encoder = new Base64Encoder(); 10 | 11 | /** 12 | * encode the input data producing a base 64 encoded byte array. 13 | * 14 | * @return a byte array containing the base 64 encoded data. 15 | */ 16 | public static byte[] encode( 17 | byte[] data) 18 | { 19 | int len = (data.length + 2) / 3 * 4; 20 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); 21 | 22 | try 23 | { 24 | encoder.encode(data, 0, data.length, bOut); 25 | } 26 | catch (IOException e) 27 | { 28 | throw new RuntimeException("exception encoding base64 string: " + e); 29 | } 30 | 31 | return bOut.toByteArray(); 32 | } 33 | 34 | /** 35 | * Encode the byte data to base 64 writing it to the given output stream. 36 | * 37 | * @return the number of bytes produced. 38 | */ 39 | public static int encode( 40 | byte[] data, 41 | OutputStream out) 42 | throws IOException 43 | { 44 | return encoder.encode(data, 0, data.length, out); 45 | } 46 | 47 | /** 48 | * Encode the byte data to base 64 writing it to the given output stream. 49 | * 50 | * @return the number of bytes produced. 51 | */ 52 | public static int encode( 53 | byte[] data, 54 | int off, 55 | int length, 56 | OutputStream out) 57 | throws IOException 58 | { 59 | return encoder.encode(data, off, length, out); 60 | } 61 | 62 | /** 63 | * decode the base 64 encoded input data. It is assumed the input data is valid. 64 | * 65 | * @return a byte array representing the decoded data. 66 | */ 67 | public static byte[] decode( 68 | byte[] data) 69 | { 70 | int len = data.length / 4 * 3; 71 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); 72 | 73 | try 74 | { 75 | encoder.decode(data, 0, data.length, bOut); 76 | } 77 | catch (IOException e) 78 | { 79 | throw new RuntimeException("exception decoding base64 string: " + e); 80 | } 81 | 82 | return bOut.toByteArray(); 83 | } 84 | 85 | /** 86 | * decode the base 64 encoded String data - whitespace will be ignored. 87 | * 88 | * @return a byte array representing the decoded data. 89 | */ 90 | public static byte[] decode( 91 | String data) 92 | { 93 | int len = data.length() / 4 * 3; 94 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); 95 | 96 | try 97 | { 98 | encoder.decode(data, bOut); 99 | } 100 | catch (IOException e) 101 | { 102 | throw new RuntimeException("exception decoding base64 string: " + e); 103 | } 104 | 105 | return bOut.toByteArray(); 106 | } 107 | 108 | /** 109 | * decode the base 64 encoded String data writing it to the given output stream, 110 | * whitespace characters will be ignored. 111 | * 112 | * @return the number of bytes produced. 113 | */ 114 | public static int decode( 115 | String data, 116 | OutputStream out) 117 | throws IOException 118 | { 119 | return encoder.decode(data, out); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1OctetString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | import com.braintree.org.bouncycastle.util.Arrays; 8 | import com.braintree.org.bouncycastle.util.encoders.Hex; 9 | 10 | public abstract class ASN1OctetString 11 | extends ASN1Object 12 | implements ASN1OctetStringParser 13 | { 14 | byte[] string; 15 | 16 | /** 17 | * return an Octet String from a tagged object. 18 | * 19 | * @param obj the tagged object holding the object we want. 20 | * @param explicit true if the object is meant to be explicitly 21 | * tagged false otherwise. 22 | * @exception IllegalArgumentException if the tagged object cannot 23 | * be converted. 24 | */ 25 | public static ASN1OctetString getInstance( 26 | ASN1TaggedObject obj, 27 | boolean explicit) 28 | { 29 | DERObject o = obj.getObject(); 30 | 31 | if (explicit || o instanceof ASN1OctetString) 32 | { 33 | return getInstance(o); 34 | } 35 | else 36 | { 37 | return BERConstructedOctetString.fromSequence(ASN1Sequence.getInstance(o)); 38 | } 39 | } 40 | 41 | /** 42 | * return an Octet String from the given object. 43 | * 44 | * @param obj the object we want converted. 45 | * @exception IllegalArgumentException if the object cannot be converted. 46 | */ 47 | public static ASN1OctetString getInstance( 48 | Object obj) 49 | { 50 | if (obj == null || obj instanceof ASN1OctetString) 51 | { 52 | return (ASN1OctetString)obj; 53 | } 54 | 55 | // TODO: this needs to be deleted in V2 56 | if (obj instanceof ASN1TaggedObject) 57 | { 58 | return getInstance(((ASN1TaggedObject)obj).getObject()); 59 | } 60 | 61 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 62 | } 63 | 64 | /** 65 | * @param string the octets making up the octet string. 66 | */ 67 | public ASN1OctetString( 68 | byte[] string) 69 | { 70 | if (string == null) 71 | { 72 | throw new NullPointerException("string cannot be null"); 73 | } 74 | this.string = string; 75 | } 76 | 77 | public ASN1OctetString( 78 | DEREncodable obj) 79 | { 80 | try 81 | { 82 | this.string = obj.getDERObject().getEncoded(ASN1Encodable.DER); 83 | } 84 | catch (IOException e) 85 | { 86 | throw new IllegalArgumentException("Error processing object : " + e.toString()); 87 | } 88 | } 89 | 90 | public InputStream getOctetStream() 91 | { 92 | return new ByteArrayInputStream(string); 93 | } 94 | 95 | public ASN1OctetStringParser parser() 96 | { 97 | return this; 98 | } 99 | 100 | public byte[] getOctets() 101 | { 102 | return string; 103 | } 104 | 105 | public int hashCode() 106 | { 107 | return Arrays.hashCode(this.getOctets()); 108 | } 109 | 110 | boolean asn1Equals( 111 | DERObject o) 112 | { 113 | if (!(o instanceof ASN1OctetString)) 114 | { 115 | return false; 116 | } 117 | 118 | ASN1OctetString other = (ASN1OctetString)o; 119 | 120 | return Arrays.areEqual(string, other.string); 121 | } 122 | 123 | public DERObject getLoadedObject() 124 | { 125 | return this.getDERObject(); 126 | } 127 | 128 | abstract void encode(DEROutputStream out) 129 | throws IOException; 130 | 131 | public String toString() 132 | { 133 | return "#"+new String(Hex.encode(string)); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/encoders/Hex.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util.encoders; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | 7 | public class Hex 8 | { 9 | private static final Encoder encoder = new HexEncoder(); 10 | 11 | /** 12 | * encode the input data producing a Hex encoded byte array. 13 | * 14 | * @return a byte array containing the Hex encoded data. 15 | */ 16 | public static byte[] encode( 17 | byte[] data) 18 | { 19 | return encode(data, 0, data.length); 20 | } 21 | 22 | /** 23 | * encode the input data producing a Hex encoded byte array. 24 | * 25 | * @return a byte array containing the Hex encoded data. 26 | */ 27 | public static byte[] encode( 28 | byte[] data, 29 | int off, 30 | int length) 31 | { 32 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 33 | 34 | try 35 | { 36 | encoder.encode(data, off, length, bOut); 37 | } 38 | catch (IOException e) 39 | { 40 | throw new RuntimeException("exception encoding Hex string: " + e); 41 | } 42 | 43 | return bOut.toByteArray(); 44 | } 45 | 46 | /** 47 | * Hex encode the byte data writing it to the given output stream. 48 | * 49 | * @return the number of bytes produced. 50 | */ 51 | public static int encode( 52 | byte[] data, 53 | OutputStream out) 54 | throws IOException 55 | { 56 | return encoder.encode(data, 0, data.length, out); 57 | } 58 | 59 | /** 60 | * Hex encode the byte data writing it to the given output stream. 61 | * 62 | * @return the number of bytes produced. 63 | */ 64 | public static int encode( 65 | byte[] data, 66 | int off, 67 | int length, 68 | OutputStream out) 69 | throws IOException 70 | { 71 | return encoder.encode(data, off, length, out); 72 | } 73 | 74 | /** 75 | * decode the Hex encoded input data. It is assumed the input data is valid. 76 | * 77 | * @return a byte array representing the decoded data. 78 | */ 79 | public static byte[] decode( 80 | byte[] data) 81 | { 82 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 83 | 84 | try 85 | { 86 | encoder.decode(data, 0, data.length, bOut); 87 | } 88 | catch (IOException e) 89 | { 90 | throw new RuntimeException("exception decoding Hex string: " + e); 91 | } 92 | 93 | return bOut.toByteArray(); 94 | } 95 | 96 | /** 97 | * decode the Hex encoded String data - whitespace will be ignored. 98 | * 99 | * @return a byte array representing the decoded data. 100 | */ 101 | public static byte[] decode( 102 | String data) 103 | { 104 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 105 | 106 | try 107 | { 108 | encoder.decode(data, bOut); 109 | } 110 | catch (IOException e) 111 | { 112 | throw new RuntimeException("exception decoding Hex string: " + e); 113 | } 114 | 115 | return bOut.toByteArray(); 116 | } 117 | 118 | /** 119 | * decode the Hex encoded String data writing it to the given output stream, 120 | * whitespace characters will be ignored. 121 | * 122 | * @return the number of bytes produced. 123 | */ 124 | public static int decode( 125 | String data, 126 | OutputStream out) 127 | throws IOException 128 | { 129 | return encoder.decode(data, out); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/LICENSE.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle; 2 | 3 | /** 4 | * The Bouncy Castle License 5 | * 6 | * Copyright (c) 2000-2008 The Legion Of The Bouncy Castle 7 | * (http://www.bouncycastle.org) 8 | *

9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | *

16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | *

19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | * SOFTWARE. 26 | */ 27 | public class LICENSE 28 | { 29 | public static String licenseText = 30 | "Copyright (c) 2000-2010 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) " 31 | + System.getProperty("line.separator") 32 | + System.getProperty("line.separator") 33 | + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software " 34 | + System.getProperty("line.separator") 35 | + "and associated documentation files (the \"Software\"), to deal in the Software without restriction, " 36 | + System.getProperty("line.separator") 37 | + "including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, " 38 | + System.getProperty("line.separator") 39 | + "and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so," 40 | + System.getProperty("line.separator") 41 | + "subject to the following conditions:" 42 | + System.getProperty("line.separator") 43 | + System.getProperty("line.separator") 44 | + "The above copyright notice and this permission notice shall be included in all copies or substantial" 45 | + System.getProperty("line.separator") 46 | + "portions of the Software." 47 | + System.getProperty("line.separator") 48 | + System.getProperty("line.separator") 49 | + "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED," 50 | + System.getProperty("line.separator") 51 | + "INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR" 52 | + System.getProperty("line.separator") 53 | + "PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE" 54 | + System.getProperty("line.separator") 55 | + "LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR" 56 | + System.getProperty("line.separator") 57 | + "OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER" 58 | + System.getProperty("line.separator") 59 | + "DEALINGS IN THE SOFTWARE."; 60 | 61 | public static void main( 62 | String[] args) 63 | { 64 | System.out.println(licenseText); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/androidTest/java/com/braintreegateway/encryption/test/RsaTest.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption.test; 2 | 3 | import java.util.Arrays; 4 | import com.braintree.org.bouncycastle.util.encoders.Base64; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.NoSuchProviderException; 7 | import java.security.InvalidKeyException; 8 | import java.security.spec.InvalidKeySpecException; 9 | import javax.crypto.NoSuchPaddingException; 10 | import javax.crypto.IllegalBlockSizeException; 11 | import javax.crypto.BadPaddingException; 12 | import android.test.AndroidTestCase; 13 | import com.braintreegateway.encryption.Rsa; 14 | import com.braintreegateway.encryption.BraintreeEncryptionException; 15 | import com.braintreegateway.encryption.util.RsaDecrypter; 16 | 17 | public class RsaTest extends AndroidTestCase { 18 | public void testRSAEncryptionUsing2048BitPublicKey() throws BraintreeEncryptionException, 19 | NoSuchAlgorithmException, 20 | InvalidKeyException, 21 | InvalidKeySpecException, 22 | IllegalBlockSizeException, 23 | NoSuchProviderException, 24 | NoSuchPaddingException, 25 | BadPaddingException { 26 | String publicKey = "MIIBCgKCAQEA8wQ3PXFYuBn9RBtOK3lW4V+7HNjik7FFd0qpPsCVd4KeiIfhuzupSevHUOLjbRSqwvAaZK3/icbBa" 27 | + "M7CMAR5y0OjAR5lmmEEkcw+A7pmKQK6XQ8j3fveJCzC3MPiNiFfr+vER7O4diTxGhoXjFFJQpzKkCwFgwhKrW8uJLmWqVhQRVNphii1G" 28 | + "pxI4fjFNc4h1w2W2CJ9kkv+9e3BnCpdVe1w7gBQZMkgjCzxbuAg8XaKlKD48M9kr8iE8kNt1eXV0jbmhCY3vZrckCUv26r2X4cD5lDvU" 29 | + "tC1Gj6jBFobm/MelAfoFqNeq+/9VyMdYfhIecQimiBYr7Vm5VH9m69TXwIDAQAB"; 30 | String privateKey = "MIIEowIBAAKCAQEA8wQ3PXFYuBn9RBtOK3lW4V+7HNjik7FFd0qpPsCVd4KeiIfhuzupSevHUOLjbRSqwvAaZK3/" 31 | + "icbBaM7CMAR5y0OjAR5lmmEEkcw+A7pmKQK6XQ8j3fveJCzC3MPiNiFfr+vER7O4diTxGhoXjFFJQpzKkCwFgwhKrW8uJLmWqVhQRVNp" 32 | + "hii1GpxI4fjFNc4h1w2W2CJ9kkv+9e3BnCpdVe1w7gBQZMkgjCzxbuAg8XaKlKD48M9kr8iE8kNt1eXV0jbmhCY3vZrckCUv26r2X4cD" 33 | + "5lDvUtC1Gj6jBFobm/MelAfoFqNeq+/9VyMdYfhIecQimiBYr7Vm5VH9m69TXwIDAQABAoIBAEvL/9LJPKvHZ2hLv/jtUrze2ASqXRlF" 34 | + "zG3lup4ZAUWSVxIsl6qHdEjbIoLHEbpfHNfKfeDzKGX3uTGQc574dmiAwyHBMl2RbxRuiNUu2VhnQmtuInjFa0cLMwgajL7nb+n19nWK" 35 | + "x7kJ0q2af8fDPr9pGgEXyexRtMEdkV3hCO3uQxA0MlX/61LK4Gssk7hlXcNw6k4fIRt9xANnN3KUrGIYtmaCk9kKsX8HhW9yrVm0WWXH" 36 | + "nzm6o5O+3BeP+3cWe+NHeRJEVEXwIPqWtdQa6e0hDtLpCQPOSlpr4yJHssT2BHpkPaHi6OnGIHa0HD7ibyfwc1KQjcwA8jg4OabmT7EC" 37 | + "gYEA/2Y1m1zG5B0nB9Mixu/3K7d+FYpBrlTKElJ0rFNcNBgvt32dPBD6E6ZrL8MokXSy8HrhhR4epQYolyfHHtpzva1gZ8XRO1wZO++T" 38 | + "fJwfUd1epDGcdMOfw++dZFW1EaWrnC3YPxrvfd/DuilwXg1QUb9aIiXCMpmQw/sm0VNk2ycCgYEA85aMzCSR2pMNip9WDQnsrP+6nYhS" 39 | + "T3BrJlJAwLNrWS9zQFfXLvufIJ0OQkdP2mAM9yN9vV8FmAt7CSAPY2UsMvKpriyv5vlqZZF7VwMr1bOaIOllBA+IIY/x3c7iF5Ezt1hJ" 40 | + "yNegjmts+Fz39G6PN1WDrCGcmcZbXOEYhs2eyQkCgYEAgANqITpqkpIuKxTgHJjQ6j+p2gAXldr4AiEETA/oalApMq6qrh3QSyMiHKmU" 41 | + "XvwAaNseyMtlDtA8bi9I9iUG2G7boIgdrMQn/cvCwDW82Rq9Qk1/n2MiZGJpII55GKRSlRDBkDffDNeo0lnM8cd4l9Dyy6TjZttkHWd4" 42 | + "eHl1VwcCgYAt9VC5T4kJUUdzyR5GNYInHdTK1iaZgF9nCovXD8MIP7CiCjC6V5UtZRSEosnJLOglVNfre9slVb0v+pGMslEFh81F5H6H" 43 | + "uLU/VpSL1ThXCJzi6sY5XujTVEJRFDCKO8YjKJA7SZusY05bCcdqodV5njPKrUjLpqYkPwAOpwr3aQKBgGie+R5Xk1t0IEdTnnY/aZHN" 44 | + "HR6fn5elFArgRN6fixx82kQDfgMaeQbtOW4Z8RxDDUeGhc11S1filfVZT2DHayoQLr6ORU/nODhHe6KedsUNFy1IRgoR1Si+2Y1g3Ijr" 45 | + "xqAFFdmgBNsxc1JMoFUDMJe2KlaF3nEk3OWuPc/A5G12"; 46 | byte[] dataToEncrypt = new String("test data").getBytes(); 47 | String encryptedData = Rsa.encrypt(dataToEncrypt, publicKey); 48 | byte[] decryptedData = RsaDecrypter.decrypt(encryptedData, privateKey); 49 | assertTrue(Arrays.equals(dataToEncrypt, Base64.decode(decryptedData))); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/BERConstructedOctetString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.util.Enumeration; 6 | import java.util.Vector; 7 | 8 | public class BERConstructedOctetString 9 | extends DEROctetString 10 | { 11 | private static final int MAX_LENGTH = 1000; 12 | 13 | /** 14 | * convert a vector of octet strings into a single byte string 15 | */ 16 | static private byte[] toBytes( 17 | Vector octs) 18 | { 19 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 20 | 21 | for (int i = 0; i != octs.size(); i++) 22 | { 23 | try 24 | { 25 | DEROctetString o = (DEROctetString)octs.elementAt(i); 26 | 27 | bOut.write(o.getOctets()); 28 | } 29 | catch (ClassCastException e) 30 | { 31 | throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString"); 32 | } 33 | catch (IOException e) 34 | { 35 | throw new IllegalArgumentException("exception converting octets " + e.toString()); 36 | } 37 | } 38 | 39 | return bOut.toByteArray(); 40 | } 41 | 42 | private Vector octs; 43 | 44 | /** 45 | * @param string the octets making up the octet string. 46 | */ 47 | public BERConstructedOctetString( 48 | byte[] string) 49 | { 50 | super(string); 51 | } 52 | 53 | public BERConstructedOctetString( 54 | Vector octs) 55 | { 56 | super(toBytes(octs)); 57 | 58 | this.octs = octs; 59 | } 60 | 61 | public BERConstructedOctetString( 62 | DERObject obj) 63 | { 64 | super(obj); 65 | } 66 | 67 | public BERConstructedOctetString( 68 | DEREncodable obj) 69 | { 70 | super(obj.getDERObject()); 71 | } 72 | 73 | public byte[] getOctets() 74 | { 75 | return string; 76 | } 77 | 78 | /** 79 | * return the DER octets that make up this string. 80 | */ 81 | public Enumeration getObjects() 82 | { 83 | if (octs == null) 84 | { 85 | return generateOcts().elements(); 86 | } 87 | 88 | return octs.elements(); 89 | } 90 | 91 | private Vector generateOcts() 92 | { 93 | Vector vec = new Vector(); 94 | for (int i = 0; i < string.length; i += MAX_LENGTH) 95 | { 96 | int end; 97 | 98 | if (i + MAX_LENGTH > string.length) 99 | { 100 | end = string.length; 101 | } 102 | else 103 | { 104 | end = i + MAX_LENGTH; 105 | } 106 | 107 | byte[] nStr = new byte[end - i]; 108 | 109 | System.arraycopy(string, i, nStr, 0, nStr.length); 110 | 111 | vec.addElement(new DEROctetString(nStr)); 112 | } 113 | 114 | return vec; 115 | } 116 | 117 | public void encode( 118 | DEROutputStream out) 119 | throws IOException 120 | { 121 | if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) 122 | { 123 | out.write(CONSTRUCTED | OCTET_STRING); 124 | 125 | out.write(0x80); 126 | 127 | // 128 | // write out the octet array 129 | // 130 | Enumeration e = getObjects(); 131 | while (e.hasMoreElements()) 132 | { 133 | out.writeObject(e.nextElement()); 134 | } 135 | 136 | out.write(0x00); 137 | out.write(0x00); 138 | } 139 | else 140 | { 141 | super.encode(out); 142 | } 143 | } 144 | 145 | public static BERConstructedOctetString fromSequence(ASN1Sequence seq) 146 | { 147 | Vector v = new Vector(); 148 | Enumeration e = seq.getObjects(); 149 | 150 | while (e.hasMoreElements()) 151 | { 152 | v.addElement(e.nextElement()); 153 | } 154 | 155 | return new BERConstructedOctetString(v); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERIA5String.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER IA5String object - this is an ascii string. 7 | */ 8 | public class DERIA5String 9 | extends ASN1Object 10 | implements DERString 11 | { 12 | String string; 13 | 14 | /** 15 | * return a IA5 string from the passed in object 16 | * 17 | * @exception IllegalArgumentException if the object cannot be converted. 18 | */ 19 | public static DERIA5String getInstance( 20 | Object obj) 21 | { 22 | if (obj == null || obj instanceof DERIA5String) 23 | { 24 | return (DERIA5String)obj; 25 | } 26 | 27 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 28 | } 29 | 30 | /** 31 | * return an IA5 String from a tagged object. 32 | * 33 | * @param obj the tagged object holding the object we want 34 | * @param explicit true if the object is meant to be explicitly 35 | * tagged false otherwise. 36 | * @exception IllegalArgumentException if the tagged object cannot 37 | * be converted. 38 | */ 39 | public static DERIA5String getInstance( 40 | ASN1TaggedObject obj, 41 | boolean explicit) 42 | { 43 | DERObject o = obj.getObject(); 44 | 45 | if (explicit || o instanceof DERIA5String) 46 | { 47 | return getInstance(o); 48 | } 49 | else 50 | { 51 | return new DERIA5String(((ASN1OctetString)o).getOctets()); 52 | } 53 | } 54 | 55 | /** 56 | * basic constructor - with bytes. 57 | */ 58 | public DERIA5String( 59 | byte[] string) 60 | { 61 | char[] cs = new char[string.length]; 62 | 63 | for (int i = 0; i != cs.length; i++) 64 | { 65 | cs[i] = (char)(string[i] & 0xff); 66 | } 67 | 68 | this.string = new String(cs); 69 | } 70 | 71 | /** 72 | * basic constructor - without validation. 73 | */ 74 | public DERIA5String( 75 | String string) 76 | { 77 | this(string, false); 78 | } 79 | 80 | /** 81 | * Constructor with optional validation. 82 | * 83 | * @param string the base string to wrap. 84 | * @param validate whether or not to check the string. 85 | * @throws IllegalArgumentException if validate is true and the string 86 | * contains characters that should not be in an IA5String. 87 | */ 88 | public DERIA5String( 89 | String string, 90 | boolean validate) 91 | { 92 | if (string == null) 93 | { 94 | throw new NullPointerException("string cannot be null"); 95 | } 96 | if (validate && !isIA5String(string)) 97 | { 98 | throw new IllegalArgumentException("string contains illegal characters"); 99 | } 100 | 101 | this.string = string; 102 | } 103 | 104 | public String getString() 105 | { 106 | return string; 107 | } 108 | 109 | public String toString() 110 | { 111 | return string; 112 | } 113 | 114 | public byte[] getOctets() 115 | { 116 | char[] cs = string.toCharArray(); 117 | byte[] bs = new byte[cs.length]; 118 | 119 | for (int i = 0; i != cs.length; i++) 120 | { 121 | bs[i] = (byte)cs[i]; 122 | } 123 | 124 | return bs; 125 | } 126 | 127 | void encode( 128 | DEROutputStream out) 129 | throws IOException 130 | { 131 | out.writeEncoded(IA5_STRING, this.getOctets()); 132 | } 133 | 134 | public int hashCode() 135 | { 136 | return this.getString().hashCode(); 137 | } 138 | 139 | boolean asn1Equals( 140 | DERObject o) 141 | { 142 | if (!(o instanceof DERIA5String)) 143 | { 144 | return false; 145 | } 146 | 147 | DERIA5String s = (DERIA5String)o; 148 | 149 | return this.getString().equals(s.getString()); 150 | } 151 | 152 | /** 153 | * return true if the passed in String can be represented without 154 | * loss as an IA5String, false otherwise. 155 | * 156 | * @return true if in printable set, false otherwise. 157 | */ 158 | public static boolean isIA5String( 159 | String str) 160 | { 161 | for (int i = str.length() - 1; i >= 0; i--) 162 | { 163 | char ch = str.charAt(i); 164 | 165 | if (ch > 0x007f) 166 | { 167 | return false; 168 | } 169 | } 170 | 171 | return true; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/encoders/HexEncoder.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util.encoders; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | 6 | public class HexEncoder 7 | implements Encoder 8 | { 9 | protected final byte[] encodingTable = 10 | { 11 | (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', 12 | (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' 13 | }; 14 | 15 | /* 16 | * set up the decoding table. 17 | */ 18 | protected final byte[] decodingTable = new byte[128]; 19 | 20 | protected void initialiseDecodingTable() 21 | { 22 | for (int i = 0; i < encodingTable.length; i++) 23 | { 24 | decodingTable[encodingTable[i]] = (byte)i; 25 | } 26 | 27 | decodingTable['A'] = decodingTable['a']; 28 | decodingTable['B'] = decodingTable['b']; 29 | decodingTable['C'] = decodingTable['c']; 30 | decodingTable['D'] = decodingTable['d']; 31 | decodingTable['E'] = decodingTable['e']; 32 | decodingTable['F'] = decodingTable['f']; 33 | } 34 | 35 | public HexEncoder() 36 | { 37 | initialiseDecodingTable(); 38 | } 39 | 40 | /** 41 | * encode the input data producing a Hex output stream. 42 | * 43 | * @return the number of bytes produced. 44 | */ 45 | public int encode( 46 | byte[] data, 47 | int off, 48 | int length, 49 | OutputStream out) 50 | throws IOException 51 | { 52 | for (int i = off; i < (off + length); i++) 53 | { 54 | int v = data[i] & 0xff; 55 | 56 | out.write(encodingTable[(v >>> 4)]); 57 | out.write(encodingTable[v & 0xf]); 58 | } 59 | 60 | return length * 2; 61 | } 62 | 63 | private boolean ignore( 64 | char c) 65 | { 66 | return (c == '\n' || c =='\r' || c == '\t' || c == ' '); 67 | } 68 | 69 | /** 70 | * decode the Hex encoded byte data writing it to the given output stream, 71 | * whitespace characters will be ignored. 72 | * 73 | * @return the number of bytes produced. 74 | */ 75 | public int decode( 76 | byte[] data, 77 | int off, 78 | int length, 79 | OutputStream out) 80 | throws IOException 81 | { 82 | byte b1, b2; 83 | int outLen = 0; 84 | 85 | int end = off + length; 86 | 87 | while (end > off) 88 | { 89 | if (!ignore((char)data[end - 1])) 90 | { 91 | break; 92 | } 93 | 94 | end--; 95 | } 96 | 97 | int i = off; 98 | while (i < end) 99 | { 100 | while (i < end && ignore((char)data[i])) 101 | { 102 | i++; 103 | } 104 | 105 | b1 = decodingTable[data[i++]]; 106 | 107 | while (i < end && ignore((char)data[i])) 108 | { 109 | i++; 110 | } 111 | 112 | b2 = decodingTable[data[i++]]; 113 | 114 | out.write((b1 << 4) | b2); 115 | 116 | outLen++; 117 | } 118 | 119 | return outLen; 120 | } 121 | 122 | /** 123 | * decode the Hex encoded String data writing it to the given output stream, 124 | * whitespace characters will be ignored. 125 | * 126 | * @return the number of bytes produced. 127 | */ 128 | public int decode( 129 | String data, 130 | OutputStream out) 131 | throws IOException 132 | { 133 | byte b1, b2; 134 | int length = 0; 135 | 136 | int end = data.length(); 137 | 138 | while (end > 0) 139 | { 140 | if (!ignore(data.charAt(end - 1))) 141 | { 142 | break; 143 | } 144 | 145 | end--; 146 | } 147 | 148 | int i = 0; 149 | while (i < end) 150 | { 151 | while (i < end && ignore(data.charAt(i))) 152 | { 153 | i++; 154 | } 155 | 156 | b1 = decodingTable[data.charAt(i++)]; 157 | 158 | while (i < end && ignore(data.charAt(i))) 159 | { 160 | i++; 161 | } 162 | 163 | b2 = decodingTable[data.charAt(i++)]; 164 | 165 | out.write((b1 << 4) | b2); 166 | 167 | length++; 168 | } 169 | 170 | return length; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERNumericString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. 7 | */ 8 | public class DERNumericString 9 | extends ASN1Object 10 | implements DERString 11 | { 12 | String string; 13 | 14 | /** 15 | * return a Numeric string from the passed in object 16 | * 17 | * @exception IllegalArgumentException if the object cannot be converted. 18 | */ 19 | public static DERNumericString getInstance( 20 | Object obj) 21 | { 22 | if (obj == null || obj instanceof DERNumericString) 23 | { 24 | return (DERNumericString)obj; 25 | } 26 | 27 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 28 | } 29 | 30 | /** 31 | * return an Numeric String from a tagged object. 32 | * 33 | * @param obj the tagged object holding the object we want 34 | * @param explicit true if the object is meant to be explicitly 35 | * tagged false otherwise. 36 | * @exception IllegalArgumentException if the tagged object cannot 37 | * be converted. 38 | */ 39 | public static DERNumericString getInstance( 40 | ASN1TaggedObject obj, 41 | boolean explicit) 42 | { 43 | DERObject o = obj.getObject(); 44 | 45 | if (explicit || o instanceof DERNumericString) 46 | { 47 | return getInstance(o); 48 | } 49 | else 50 | { 51 | return new DERNumericString(ASN1OctetString.getInstance(o).getOctets()); 52 | } 53 | } 54 | 55 | /** 56 | * basic constructor - with bytes. 57 | */ 58 | public DERNumericString( 59 | byte[] string) 60 | { 61 | char[] cs = new char[string.length]; 62 | 63 | for (int i = 0; i != cs.length; i++) 64 | { 65 | cs[i] = (char)(string[i] & 0xff); 66 | } 67 | 68 | this.string = new String(cs); 69 | } 70 | 71 | /** 72 | * basic constructor - without validation.. 73 | */ 74 | public DERNumericString( 75 | String string) 76 | { 77 | this(string, false); 78 | } 79 | 80 | /** 81 | * Constructor with optional validation. 82 | * 83 | * @param string the base string to wrap. 84 | * @param validate whether or not to check the string. 85 | * @throws IllegalArgumentException if validate is true and the string 86 | * contains characters that should not be in a NumericString. 87 | */ 88 | public DERNumericString( 89 | String string, 90 | boolean validate) 91 | { 92 | if (validate && !isNumericString(string)) 93 | { 94 | throw new IllegalArgumentException("string contains illegal characters"); 95 | } 96 | 97 | this.string = string; 98 | } 99 | 100 | public String getString() 101 | { 102 | return string; 103 | } 104 | 105 | public String toString() 106 | { 107 | return string; 108 | } 109 | 110 | public byte[] getOctets() 111 | { 112 | char[] cs = string.toCharArray(); 113 | byte[] bs = new byte[cs.length]; 114 | 115 | for (int i = 0; i != cs.length; i++) 116 | { 117 | bs[i] = (byte)cs[i]; 118 | } 119 | 120 | return bs; 121 | } 122 | 123 | void encode( 124 | DEROutputStream out) 125 | throws IOException 126 | { 127 | out.writeEncoded(NUMERIC_STRING, this.getOctets()); 128 | } 129 | 130 | public int hashCode() 131 | { 132 | return this.getString().hashCode(); 133 | } 134 | 135 | boolean asn1Equals( 136 | DERObject o) 137 | { 138 | if (!(o instanceof DERNumericString)) 139 | { 140 | return false; 141 | } 142 | 143 | DERNumericString s = (DERNumericString)o; 144 | 145 | return this.getString().equals(s.getString()); 146 | } 147 | 148 | /** 149 | * Return true if the string can be represented as a NumericString ('0'..'9', ' ') 150 | * 151 | * @param str string to validate. 152 | * @return true if numeric, fale otherwise. 153 | */ 154 | public static boolean isNumericString( 155 | String str) 156 | { 157 | for (int i = str.length() - 1; i >= 0; i--) 158 | { 159 | char ch = str.charAt(i); 160 | 161 | if (ch > 0x007f) 162 | { 163 | return false; 164 | } 165 | 166 | if (('0' <= ch && ch <= '9') || ch == ' ') 167 | { 168 | continue; 169 | } 170 | 171 | return false; 172 | } 173 | 174 | return true; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/androidTest/java/com/braintreegateway/encryption/test/BraintreeTest.java: -------------------------------------------------------------------------------- 1 | package com.braintreegateway.encryption.test; 2 | 3 | import android.test.AndroidTestCase; 4 | 5 | import com.braintreegateway.encryption.Braintree; 6 | import com.braintreegateway.encryption.BraintreeEncryptionException; 7 | import com.braintreegateway.encryption.util.AesDecrypter; 8 | import com.braintreegateway.encryption.util.RsaDecrypter; 9 | 10 | import java.security.InvalidAlgorithmParameterException; 11 | import java.security.InvalidKeyException; 12 | import java.security.NoSuchAlgorithmException; 13 | import java.security.NoSuchProviderException; 14 | import java.security.spec.InvalidKeySpecException; 15 | import java.util.Arrays; 16 | 17 | import javax.crypto.BadPaddingException; 18 | import javax.crypto.IllegalBlockSizeException; 19 | import javax.crypto.NoSuchPaddingException; 20 | 21 | public class BraintreeTest extends AndroidTestCase { 22 | private String publicKey = "MIIBCgKCAQEA8wQ3PXFYuBn9RBtOK3lW4V+7HNjik7FFd0qpPsCVd4KeiIfhuzupSevHUOLjbRSqwvAaZK3/icbBaM7CM" 23 | + "AR5y0OjAR5lmmEEkcw+A7pmKQK6XQ8j3fveJCzC3MPiNiFfr+vER7O4diTxGhoXjFFJQpzKkCwFgwhKrW8uJLmWqVhQRVNphii1GpxI4fjFNc4" 24 | + "h1w2W2CJ9kkv+9e3BnCpdVe1w7gBQZMkgjCzxbuAg8XaKlKD48M9kr8iE8kNt1eXV0jbmhCY3vZrckCUv26r2X4cD5lDvUtC1Gj6jBFobm/Mel" 25 | + "AfoFqNeq+/9VyMdYfhIecQimiBYr7Vm5VH9m69TXwIDAQAB"; 26 | private String privateKey = "MIIEowIBAAKCAQEA8wQ3PXFYuBn9RBtOK3lW4V+7HNjik7FFd0qpPsCVd4KeiIfhuzupSevHUOLjbRSqwvAaZK3/icbB" 27 | + "aM7CMAR5y0OjAR5lmmEEkcw+A7pmKQK6XQ8j3fveJCzC3MPiNiFfr+vER7O4diTxGhoXjFFJQpzKkCwFgwhKrW8uJLmWqVhQRVNphii1GpxI4f" 28 | + "jFNc4h1w2W2CJ9kkv+9e3BnCpdVe1w7gBQZMkgjCzxbuAg8XaKlKD48M9kr8iE8kNt1eXV0jbmhCY3vZrckCUv26r2X4cD5lDvUtC1Gj6jBFob" 29 | + "m/MelAfoFqNeq+/9VyMdYfhIecQimiBYr7Vm5VH9m69TXwIDAQABAoIBAEvL/9LJPKvHZ2hLv/jtUrze2ASqXRlFzG3lup4ZAUWSVxIsl6qHdE" 30 | + "jbIoLHEbpfHNfKfeDzKGX3uTGQc574dmiAwyHBMl2RbxRuiNUu2VhnQmtuInjFa0cLMwgajL7nb+n19nWKx7kJ0q2af8fDPr9pGgEXyexRtMEd" 31 | + "kV3hCO3uQxA0MlX/61LK4Gssk7hlXcNw6k4fIRt9xANnN3KUrGIYtmaCk9kKsX8HhW9yrVm0WWXHnzm6o5O+3BeP+3cWe+NHeRJEVEXwIPqWtd" 32 | + "Qa6e0hDtLpCQPOSlpr4yJHssT2BHpkPaHi6OnGIHa0HD7ibyfwc1KQjcwA8jg4OabmT7ECgYEA/2Y1m1zG5B0nB9Mixu/3K7d+FYpBrlTKElJ0" 33 | + "rFNcNBgvt32dPBD6E6ZrL8MokXSy8HrhhR4epQYolyfHHtpzva1gZ8XRO1wZO++TfJwfUd1epDGcdMOfw++dZFW1EaWrnC3YPxrvfd/DuilwXg" 34 | + "1QUb9aIiXCMpmQw/sm0VNk2ycCgYEA85aMzCSR2pMNip9WDQnsrP+6nYhST3BrJlJAwLNrWS9zQFfXLvufIJ0OQkdP2mAM9yN9vV8FmAt7CSAP" 35 | + "Y2UsMvKpriyv5vlqZZF7VwMr1bOaIOllBA+IIY/x3c7iF5Ezt1hJyNegjmts+Fz39G6PN1WDrCGcmcZbXOEYhs2eyQkCgYEAgANqITpqkpIuKx" 36 | + "TgHJjQ6j+p2gAXldr4AiEETA/oalApMq6qrh3QSyMiHKmUXvwAaNseyMtlDtA8bi9I9iUG2G7boIgdrMQn/cvCwDW82Rq9Qk1/n2MiZGJpII55" 37 | + "GKRSlRDBkDffDNeo0lnM8cd4l9Dyy6TjZttkHWd4eHl1VwcCgYAt9VC5T4kJUUdzyR5GNYInHdTK1iaZgF9nCovXD8MIP7CiCjC6V5UtZRSEos" 38 | + "nJLOglVNfre9slVb0v+pGMslEFh81F5H6HuLU/VpSL1ThXCJzi6sY5XujTVEJRFDCKO8YjKJA7SZusY05bCcdqodV5njPKrUjLpqYkPwAOpwr3" 39 | + "aQKBgGie+R5Xk1t0IEdTnnY/aZHNHR6fn5elFArgRN6fixx82kQDfgMaeQbtOW4Z8RxDDUeGhc11S1filfVZT2DHayoQLr6ORU/nODhHe6Keds" 40 | + "UNFy1IRgoR1Si+2Y1g3IjrxqAFFdmgBNsxc1JMoFUDMJe2KlaF3nEk3OWuPc/A5G12"; 41 | private String encryptedPrefix; 42 | private Braintree braintree; 43 | private String dataToEncrypt = "test data"; 44 | 45 | @Override 46 | public void setUp() { 47 | braintree = new Braintree(publicKey); 48 | String formattedVersion = BuildConfig.VERSION_NAME.replace(".", "_"); 49 | encryptedPrefix = "$bt3|android_" + formattedVersion + "$"; 50 | } 51 | 52 | public void testHasAPublicKey() { 53 | assertEquals(publicKey, braintree.getPublicKey()); 54 | } 55 | 56 | public void testEncryptedDataPrependsWithPlatformAndVersion() throws BraintreeEncryptionException { 57 | String encryptedData = braintree.encrypt(dataToEncrypt); 58 | assertEquals(encryptedPrefix, encryptedData.substring(0, encryptedPrefix.length())); 59 | } 60 | 61 | public void testBraintreeEncryption() throws BraintreeEncryptionException, 62 | NoSuchAlgorithmException, 63 | InvalidKeyException, 64 | InvalidKeySpecException, 65 | IllegalBlockSizeException, 66 | NoSuchProviderException, 67 | NoSuchPaddingException, 68 | BadPaddingException, 69 | InvalidAlgorithmParameterException { 70 | String encryptedData = braintree.encrypt(dataToEncrypt); 71 | String encryptedAesKeyAndCipherText = encryptedData.substring(encryptedPrefix.length()); 72 | String encryptedAesKey = encryptedAesKeyAndCipherText.split("\\$")[0]; 73 | String encryptedIvAndCipherText = encryptedAesKeyAndCipherText.split("\\$")[1]; 74 | 75 | byte[] aesKey = RsaDecrypter.decrypt(encryptedAesKey, privateKey); 76 | byte[] decryptedData = AesDecrypter.decrypt(encryptedIvAndCipherText, aesKey); 77 | assertTrue(Arrays.equals(dataToEncrypt.getBytes(), decryptedData)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/util/Arrays.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.util; 2 | 3 | /** 4 | * General array utilities. 5 | */ 6 | public final class Arrays 7 | { 8 | private Arrays() 9 | { 10 | // static class, hide constructor 11 | } 12 | 13 | public static boolean areEqual( 14 | boolean[] a, 15 | boolean[] b) 16 | { 17 | if (a == b) 18 | { 19 | return true; 20 | } 21 | 22 | if (a == null || b == null) 23 | { 24 | return false; 25 | } 26 | 27 | if (a.length != b.length) 28 | { 29 | return false; 30 | } 31 | 32 | for (int i = 0; i != a.length; i++) 33 | { 34 | if (a[i] != b[i]) 35 | { 36 | return false; 37 | } 38 | } 39 | 40 | return true; 41 | } 42 | 43 | public static boolean areEqual( 44 | char[] a, 45 | char[] b) 46 | { 47 | if (a == b) 48 | { 49 | return true; 50 | } 51 | 52 | if (a == null || b == null) 53 | { 54 | return false; 55 | } 56 | 57 | if (a.length != b.length) 58 | { 59 | return false; 60 | } 61 | 62 | for (int i = 0; i != a.length; i++) 63 | { 64 | if (a[i] != b[i]) 65 | { 66 | return false; 67 | } 68 | } 69 | 70 | return true; 71 | } 72 | 73 | public static boolean areEqual( 74 | byte[] a, 75 | byte[] b) 76 | { 77 | if (a == b) 78 | { 79 | return true; 80 | } 81 | 82 | if (a == null || b == null) 83 | { 84 | return false; 85 | } 86 | 87 | if (a.length != b.length) 88 | { 89 | return false; 90 | } 91 | 92 | for (int i = 0; i != a.length; i++) 93 | { 94 | if (a[i] != b[i]) 95 | { 96 | return false; 97 | } 98 | } 99 | 100 | return true; 101 | } 102 | 103 | /** 104 | * A constant time equals comparison - does not terminate early if 105 | * test will fail. 106 | * 107 | * @param a first array 108 | * @param b second array 109 | * @return true if arrays equal, false otherwise. 110 | */ 111 | public static boolean constantTimeAreEqual( 112 | byte[] a, 113 | byte[] b) 114 | { 115 | if (a == b) 116 | { 117 | return true; 118 | } 119 | 120 | if (a == null || b == null) 121 | { 122 | return false; 123 | } 124 | 125 | if (a.length != b.length) 126 | { 127 | return false; 128 | } 129 | 130 | int nonEqual = 0; 131 | 132 | for (int i = 0; i != a.length; i++) 133 | { 134 | nonEqual |= (a[i] ^ b[i]); 135 | } 136 | 137 | return nonEqual == 0; 138 | } 139 | 140 | public static boolean areEqual( 141 | int[] a, 142 | int[] b) 143 | { 144 | if (a == b) 145 | { 146 | return true; 147 | } 148 | 149 | if (a == null || b == null) 150 | { 151 | return false; 152 | } 153 | 154 | if (a.length != b.length) 155 | { 156 | return false; 157 | } 158 | 159 | for (int i = 0; i != a.length; i++) 160 | { 161 | if (a[i] != b[i]) 162 | { 163 | return false; 164 | } 165 | } 166 | 167 | return true; 168 | } 169 | 170 | public static void fill( 171 | byte[] array, 172 | byte value) 173 | { 174 | for (int i = 0; i < array.length; i++) 175 | { 176 | array[i] = value; 177 | } 178 | } 179 | 180 | public static void fill( 181 | long[] array, 182 | long value) 183 | { 184 | for (int i = 0; i < array.length; i++) 185 | { 186 | array[i] = value; 187 | } 188 | } 189 | 190 | public static void fill( 191 | short[] array, 192 | short value) 193 | { 194 | for (int i = 0; i < array.length; i++) 195 | { 196 | array[i] = value; 197 | } 198 | } 199 | 200 | public static int hashCode(byte[] data) 201 | { 202 | if (data == null) 203 | { 204 | return 0; 205 | } 206 | 207 | int i = data.length; 208 | int hc = i + 1; 209 | 210 | while (--i >= 0) 211 | { 212 | hc *= 257; 213 | hc ^= data[i]; 214 | } 215 | 216 | return hc; 217 | } 218 | 219 | public static byte[] clone(byte[] data) 220 | { 221 | if (data == null) 222 | { 223 | return null; 224 | } 225 | byte[] copy = new byte[data.length]; 226 | 227 | System.arraycopy(data, 0, copy, 0, data.length); 228 | 229 | return copy; 230 | } 231 | 232 | public static int[] clone(int[] data) 233 | { 234 | if (data == null) 235 | { 236 | return null; 237 | } 238 | int[] copy = new int[data.length]; 239 | 240 | System.arraycopy(data, 0, copy, 0, data.length); 241 | 242 | return copy; 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERPrintableString.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * DER PrintableString object. 7 | */ 8 | public class DERPrintableString 9 | extends ASN1Object 10 | implements DERString 11 | { 12 | String string; 13 | 14 | /** 15 | * return a printable string from the passed in object. 16 | * 17 | * @exception IllegalArgumentException if the object cannot be converted. 18 | */ 19 | public static DERPrintableString getInstance( 20 | Object obj) 21 | { 22 | if (obj == null || obj instanceof DERPrintableString) 23 | { 24 | return (DERPrintableString)obj; 25 | } 26 | 27 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 28 | } 29 | 30 | /** 31 | * return a Printable String from a tagged object. 32 | * 33 | * @param obj the tagged object holding the object we want 34 | * @param explicit true if the object is meant to be explicitly 35 | * tagged false otherwise. 36 | * @exception IllegalArgumentException if the tagged object cannot 37 | * be converted. 38 | */ 39 | public static DERPrintableString getInstance( 40 | ASN1TaggedObject obj, 41 | boolean explicit) 42 | { 43 | DERObject o = obj.getObject(); 44 | 45 | if (explicit || o instanceof DERPrintableString) 46 | { 47 | return getInstance(o); 48 | } 49 | else 50 | { 51 | return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets()); 52 | } 53 | } 54 | 55 | /** 56 | * basic constructor - byte encoded string. 57 | */ 58 | public DERPrintableString( 59 | byte[] string) 60 | { 61 | char[] cs = new char[string.length]; 62 | 63 | for (int i = 0; i != cs.length; i++) 64 | { 65 | cs[i] = (char)(string[i] & 0xff); 66 | } 67 | 68 | this.string = new String(cs); 69 | } 70 | 71 | /** 72 | * basic constructor - this does not validate the string 73 | */ 74 | public DERPrintableString( 75 | String string) 76 | { 77 | this(string, false); 78 | } 79 | 80 | /** 81 | * Constructor with optional validation. 82 | * 83 | * @param string the base string to wrap. 84 | * @param validate whether or not to check the string. 85 | * @throws IllegalArgumentException if validate is true and the string 86 | * contains characters that should not be in a PrintableString. 87 | */ 88 | public DERPrintableString( 89 | String string, 90 | boolean validate) 91 | { 92 | if (validate && !isPrintableString(string)) 93 | { 94 | throw new IllegalArgumentException("string contains illegal characters"); 95 | } 96 | 97 | this.string = string; 98 | } 99 | 100 | public String getString() 101 | { 102 | return string; 103 | } 104 | 105 | public byte[] getOctets() 106 | { 107 | char[] cs = string.toCharArray(); 108 | byte[] bs = new byte[cs.length]; 109 | 110 | for (int i = 0; i != cs.length; i++) 111 | { 112 | bs[i] = (byte)cs[i]; 113 | } 114 | 115 | return bs; 116 | } 117 | 118 | void encode( 119 | DEROutputStream out) 120 | throws IOException 121 | { 122 | out.writeEncoded(PRINTABLE_STRING, this.getOctets()); 123 | } 124 | 125 | public int hashCode() 126 | { 127 | return this.getString().hashCode(); 128 | } 129 | 130 | boolean asn1Equals( 131 | DERObject o) 132 | { 133 | if (!(o instanceof DERPrintableString)) 134 | { 135 | return false; 136 | } 137 | 138 | DERPrintableString s = (DERPrintableString)o; 139 | 140 | return this.getString().equals(s.getString()); 141 | } 142 | 143 | public String toString() 144 | { 145 | return string; 146 | } 147 | 148 | /** 149 | * return true if the passed in String can be represented without 150 | * loss as a PrintableString, false otherwise. 151 | * 152 | * @return true if in printable set, false otherwise. 153 | */ 154 | public static boolean isPrintableString( 155 | String str) 156 | { 157 | for (int i = str.length() - 1; i >= 0; i--) 158 | { 159 | char ch = str.charAt(i); 160 | 161 | if (ch > 0x007f) 162 | { 163 | return false; 164 | } 165 | 166 | if ('a' <= ch && ch <= 'z') 167 | { 168 | continue; 169 | } 170 | 171 | if ('A' <= ch && ch <= 'Z') 172 | { 173 | continue; 174 | } 175 | 176 | if ('0' <= ch && ch <= '9') 177 | { 178 | continue; 179 | } 180 | 181 | switch (ch) 182 | { 183 | case ' ': 184 | case '\'': 185 | case '(': 186 | case ')': 187 | case '+': 188 | case '-': 189 | case '.': 190 | case ':': 191 | case '=': 192 | case '?': 193 | case '/': 194 | case ',': 195 | continue; 196 | } 197 | 198 | return false; 199 | } 200 | 201 | return true; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1TaggedObject.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by 7 | * a [n] where n is some number - these are assumed to follow the construction 8 | * rules (as with sequences). 9 | */ 10 | public abstract class ASN1TaggedObject 11 | extends ASN1Object 12 | implements ASN1TaggedObjectParser 13 | { 14 | int tagNo; 15 | boolean empty = false; 16 | boolean explicit = true; 17 | DEREncodable obj = null; 18 | 19 | static public ASN1TaggedObject getInstance( 20 | ASN1TaggedObject obj, 21 | boolean explicit) 22 | { 23 | if (explicit) 24 | { 25 | return (ASN1TaggedObject)obj.getObject(); 26 | } 27 | 28 | throw new IllegalArgumentException("implicitly tagged tagged object"); 29 | } 30 | 31 | static public ASN1TaggedObject getInstance( 32 | Object obj) 33 | { 34 | if (obj == null || obj instanceof ASN1TaggedObject) 35 | { 36 | return (ASN1TaggedObject)obj; 37 | } 38 | 39 | throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 40 | } 41 | 42 | /** 43 | * Create a tagged object in the explicit style. 44 | * 45 | * @param tagNo the tag number for this object. 46 | * @param obj the tagged object. 47 | */ 48 | public ASN1TaggedObject( 49 | int tagNo, 50 | DEREncodable obj) 51 | { 52 | this.explicit = true; 53 | this.tagNo = tagNo; 54 | this.obj = obj; 55 | } 56 | 57 | /** 58 | * Create a tagged object with the style given by the value of explicit. 59 | *

60 | * If the object implements ASN1Choice the tag style will always be changed 61 | * to explicit in accordance with the ASN.1 encoding rules. 62 | *

63 | * @param explicit true if the object is explicitly tagged. 64 | * @param tagNo the tag number for this object. 65 | * @param obj the tagged object. 66 | */ 67 | public ASN1TaggedObject( 68 | boolean explicit, 69 | int tagNo, 70 | DEREncodable obj) 71 | { 72 | if (obj instanceof ASN1Choice) 73 | { 74 | this.explicit = true; 75 | } 76 | else 77 | { 78 | this.explicit = explicit; 79 | } 80 | 81 | this.tagNo = tagNo; 82 | this.obj = obj; 83 | } 84 | 85 | boolean asn1Equals( 86 | DERObject o) 87 | { 88 | if (!(o instanceof ASN1TaggedObject)) 89 | { 90 | return false; 91 | } 92 | 93 | ASN1TaggedObject other = (ASN1TaggedObject)o; 94 | 95 | if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) 96 | { 97 | return false; 98 | } 99 | 100 | if(obj == null) 101 | { 102 | if (other.obj != null) 103 | { 104 | return false; 105 | } 106 | } 107 | else 108 | { 109 | if (!(obj.getDERObject().equals(other.obj.getDERObject()))) 110 | { 111 | return false; 112 | } 113 | } 114 | 115 | return true; 116 | } 117 | 118 | public int hashCode() 119 | { 120 | int code = tagNo; 121 | 122 | // TODO: actually this is wrong - the problem is that a re-encoded 123 | // object may end up with a different hashCode due to implicit 124 | // tagging. As implicit tagging is ambiguous if a sequence is involved 125 | // it seems the only correct method for both equals and hashCode is to 126 | // compare the encodings... 127 | if (obj != null) 128 | { 129 | code ^= obj.hashCode(); 130 | } 131 | 132 | return code; 133 | } 134 | 135 | public int getTagNo() 136 | { 137 | return tagNo; 138 | } 139 | 140 | /** 141 | * return whether or not the object may be explicitly tagged. 142 | *

143 | * Note: if the object has been read from an input stream, the only 144 | * time you can be sure if isExplicit is returning the true state of 145 | * affairs is if it returns false. An implicitly tagged object may appear 146 | * to be explicitly tagged, so you need to understand the context under 147 | * which the reading was done as well, see getObject below. 148 | */ 149 | public boolean isExplicit() 150 | { 151 | return explicit; 152 | } 153 | 154 | public boolean isEmpty() 155 | { 156 | return empty; 157 | } 158 | 159 | /** 160 | * return whatever was following the tag. 161 | *

162 | * Note: tagged objects are generally context dependent if you're 163 | * trying to extract a tagged object you should be going via the 164 | * appropriate getInstance method. 165 | */ 166 | public DERObject getObject() 167 | { 168 | if (obj != null) 169 | { 170 | return obj.getDERObject(); 171 | } 172 | 173 | return null; 174 | } 175 | 176 | /** 177 | * Return the object held in this tagged object as a parser assuming it has 178 | * the type of the passed in tag. If the object doesn't have a parser 179 | * associated with it, the base object is returned. 180 | */ 181 | public DEREncodable getObjectParser( 182 | int tag, 183 | boolean isExplicit) 184 | { 185 | switch (tag) 186 | { 187 | case DERTags.SET: 188 | return ASN1Set.getInstance(this, isExplicit).parser(); 189 | case DERTags.SEQUENCE: 190 | return ASN1Sequence.getInstance(this, isExplicit).parser(); 191 | case DERTags.OCTET_STRING: 192 | return ASN1OctetString.getInstance(this, isExplicit).parser(); 193 | } 194 | 195 | if (isExplicit) 196 | { 197 | return getObject(); 198 | } 199 | 200 | throw new RuntimeException("implicit tagging not implemented for tag: " + tag); 201 | } 202 | 203 | public DERObject getLoadedObject() 204 | { 205 | return this.getDERObject(); 206 | } 207 | 208 | abstract void encode(DEROutputStream out) 209 | throws IOException; 210 | 211 | public String toString() 212 | { 213 | return "[" + tagNo + "]" + obj; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERApplicationSpecific.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | import com.braintree.org.bouncycastle.util.Arrays; 7 | 8 | /** 9 | * Base class for an application specific object 10 | */ 11 | public class DERApplicationSpecific 12 | extends ASN1Object 13 | { 14 | private final boolean isConstructed; 15 | private final int tag; 16 | private final byte[] octets; 17 | 18 | DERApplicationSpecific( 19 | boolean isConstructed, 20 | int tag, 21 | byte[] octets) 22 | { 23 | this.isConstructed = isConstructed; 24 | this.tag = tag; 25 | this.octets = octets; 26 | } 27 | 28 | public DERApplicationSpecific( 29 | int tag, 30 | byte[] octets) 31 | { 32 | this(false, tag, octets); 33 | } 34 | 35 | public DERApplicationSpecific( 36 | int tag, 37 | DEREncodable object) 38 | throws IOException 39 | { 40 | this(true, tag, object); 41 | } 42 | 43 | public DERApplicationSpecific( 44 | boolean explicit, 45 | int tag, 46 | DEREncodable object) 47 | throws IOException 48 | { 49 | byte[] data = object.getDERObject().getDEREncoded(); 50 | 51 | this.isConstructed = explicit; 52 | this.tag = tag; 53 | 54 | if (explicit) 55 | { 56 | this.octets = data; 57 | } 58 | else 59 | { 60 | int lenBytes = getLengthOfLength(data); 61 | byte[] tmp = new byte[data.length - lenBytes]; 62 | System.arraycopy(data, lenBytes, tmp, 0, tmp.length); 63 | this.octets = tmp; 64 | } 65 | } 66 | 67 | public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec) 68 | { 69 | this.tag = tagNo; 70 | this.isConstructed = true; 71 | ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 72 | 73 | for (int i = 0; i != vec.size(); i++) 74 | { 75 | try 76 | { 77 | bOut.write(((ASN1Encodable)vec.get(i)).getEncoded()); 78 | } 79 | catch (IOException e) 80 | { 81 | throw new ASN1ParsingException("malformed object: " + e, e); 82 | } 83 | } 84 | this.octets = bOut.toByteArray(); 85 | } 86 | 87 | private int getLengthOfLength(byte[] data) 88 | { 89 | int count = 2; // TODO: assumes only a 1 byte tag number 90 | 91 | while((data[count - 1] & 0x80) != 0) 92 | { 93 | count++; 94 | } 95 | 96 | return count; 97 | } 98 | 99 | public boolean isConstructed() 100 | { 101 | return isConstructed; 102 | } 103 | 104 | public byte[] getContents() 105 | { 106 | return octets; 107 | } 108 | 109 | public int getApplicationTag() 110 | { 111 | return tag; 112 | } 113 | 114 | /** 115 | * Return the enclosed object assuming explicit tagging. 116 | * 117 | * @return the resulting object 118 | * @throws IOException if reconstruction fails. 119 | */ 120 | public DERObject getObject() 121 | throws IOException 122 | { 123 | return new ASN1InputStream(getContents()).readObject(); 124 | } 125 | 126 | /** 127 | * Return the enclosed object assuming implicit tagging. 128 | * 129 | * @param derTagNo the type tag that should be applied to the object's contents. 130 | * @return the resulting object 131 | * @throws IOException if reconstruction fails. 132 | */ 133 | public DERObject getObject(int derTagNo) 134 | throws IOException 135 | { 136 | if (derTagNo >= 0x1f) 137 | { 138 | throw new IOException("unsupported tag number"); 139 | } 140 | 141 | byte[] orig = this.getEncoded(); 142 | byte[] tmp = replaceTagNumber(derTagNo, orig); 143 | 144 | if ((orig[0] & DERTags.CONSTRUCTED) != 0) 145 | { 146 | tmp[0] |= DERTags.CONSTRUCTED; 147 | } 148 | 149 | return new ASN1InputStream(tmp).readObject(); 150 | } 151 | 152 | /* (non-Javadoc) 153 | * @see org.bouncycastle.asn1.DERObject#encode(org.bouncycastle.asn1.DEROutputStream) 154 | */ 155 | void encode(DEROutputStream out) throws IOException 156 | { 157 | int classBits = DERTags.APPLICATION; 158 | if (isConstructed) 159 | { 160 | classBits |= DERTags.CONSTRUCTED; 161 | } 162 | 163 | out.writeEncoded(classBits, tag, octets); 164 | } 165 | 166 | boolean asn1Equals( 167 | DERObject o) 168 | { 169 | if (!(o instanceof DERApplicationSpecific)) 170 | { 171 | return false; 172 | } 173 | 174 | DERApplicationSpecific other = (DERApplicationSpecific)o; 175 | 176 | return isConstructed == other.isConstructed 177 | && tag == other.tag 178 | && Arrays.areEqual(octets, other.octets); 179 | } 180 | 181 | public int hashCode() 182 | { 183 | return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets); 184 | } 185 | 186 | private byte[] replaceTagNumber(int newTag, byte[] input) 187 | throws IOException 188 | { 189 | int tagNo = input[0] & 0x1f; 190 | int index = 1; 191 | // 192 | // with tagged object tag number is bottom 5 bits, or stored at the start of the content 193 | // 194 | if (tagNo == 0x1f) 195 | { 196 | tagNo = 0; 197 | 198 | int b = input[index++] & 0xff; 199 | 200 | // X.690-0207 8.1.2.4.2 201 | // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." 202 | if ((b & 0x7f) == 0) // Note: -1 will pass 203 | { 204 | throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); 205 | } 206 | 207 | while ((b >= 0) && ((b & 0x80) != 0)) 208 | { 209 | tagNo |= (b & 0x7f); 210 | tagNo <<= 7; 211 | b = input[index++] & 0xff; 212 | } 213 | 214 | tagNo |= (b & 0x7f); 215 | } 216 | 217 | byte[] tmp = new byte[input.length - index + 1]; 218 | 219 | System.arraycopy(input, index, tmp, 1, tmp.length - 1); 220 | 221 | tmp[0] = (byte)newTag; 222 | 223 | return tmp; 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/ASN1Sequence.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.util.Enumeration; 5 | import java.util.Vector; 6 | 7 | public abstract class ASN1Sequence 8 | extends ASN1Object 9 | { 10 | private Vector seq = new Vector(); 11 | 12 | /** 13 | * return an ASN1Sequence from the given object. 14 | * 15 | * @param obj the object we want converted. 16 | * @exception IllegalArgumentException if the object cannot be converted. 17 | */ 18 | public static ASN1Sequence getInstance( 19 | Object obj) 20 | { 21 | if (obj == null || obj instanceof ASN1Sequence) 22 | { 23 | return (ASN1Sequence)obj; 24 | } 25 | else if (obj instanceof byte[]) 26 | { 27 | try 28 | { 29 | return ASN1Sequence.getInstance(ASN1Object.fromByteArray((byte[])obj)); 30 | } 31 | catch (IOException e) 32 | { 33 | throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); 34 | } 35 | } 36 | 37 | throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 38 | } 39 | 40 | /** 41 | * Return an ASN1 sequence from a tagged object. There is a special 42 | * case here, if an object appears to have been explicitly tagged on 43 | * reading but we were expecting it to be implicitly tagged in the 44 | * normal course of events it indicates that we lost the surrounding 45 | * sequence - so we need to add it back (this will happen if the tagged 46 | * object is a sequence that contains other sequences). If you are 47 | * dealing with implicitly tagged sequences you really should 48 | * be using this method. 49 | * 50 | * @param obj the tagged object. 51 | * @param explicit true if the object is meant to be explicitly tagged, 52 | * false otherwise. 53 | * @exception IllegalArgumentException if the tagged object cannot 54 | * be converted. 55 | */ 56 | public static ASN1Sequence getInstance( 57 | ASN1TaggedObject obj, 58 | boolean explicit) 59 | { 60 | if (explicit) 61 | { 62 | if (!obj.isExplicit()) 63 | { 64 | throw new IllegalArgumentException("object implicit - explicit expected."); 65 | } 66 | 67 | return (ASN1Sequence)obj.getObject(); 68 | } 69 | else 70 | { 71 | // 72 | // constructed object which appears to be explicitly tagged 73 | // when it should be implicit means we have to add the 74 | // surrounding sequence. 75 | // 76 | if (obj.isExplicit()) 77 | { 78 | if (obj instanceof BERTaggedObject) 79 | { 80 | return new BERSequence(obj.getObject()); 81 | } 82 | else 83 | { 84 | return new DERSequence(obj.getObject()); 85 | } 86 | } 87 | else 88 | { 89 | if (obj.getObject() instanceof ASN1Sequence) 90 | { 91 | return (ASN1Sequence)obj.getObject(); 92 | } 93 | } 94 | } 95 | 96 | throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); 97 | } 98 | 99 | public Enumeration getObjects() 100 | { 101 | return seq.elements(); 102 | } 103 | 104 | public ASN1SequenceParser parser() 105 | { 106 | final ASN1Sequence outer = this; 107 | 108 | return new ASN1SequenceParser() 109 | { 110 | private final int max = size(); 111 | 112 | private int index; 113 | 114 | public DEREncodable readObject() throws IOException 115 | { 116 | if (index == max) 117 | { 118 | return null; 119 | } 120 | 121 | DEREncodable obj = getObjectAt(index++); 122 | if (obj instanceof ASN1Sequence) 123 | { 124 | return ((ASN1Sequence)obj).parser(); 125 | } 126 | if (obj instanceof ASN1Set) 127 | { 128 | return ((ASN1Set)obj).parser(); 129 | } 130 | 131 | return obj; 132 | } 133 | 134 | public DERObject getLoadedObject() 135 | { 136 | return outer; 137 | } 138 | 139 | public DERObject getDERObject() 140 | { 141 | return outer; 142 | } 143 | }; 144 | } 145 | 146 | /** 147 | * return the object at the sequence position indicated by index. 148 | * 149 | * @param index the sequence number (starting at zero) of the object 150 | * @return the object at the sequence position indicated by index. 151 | */ 152 | public DEREncodable getObjectAt( 153 | int index) 154 | { 155 | return (DEREncodable)seq.elementAt(index); 156 | } 157 | 158 | /** 159 | * return the number of objects in this sequence. 160 | * 161 | * @return the number of objects in this sequence. 162 | */ 163 | public int size() 164 | { 165 | return seq.size(); 166 | } 167 | 168 | public int hashCode() 169 | { 170 | Enumeration e = this.getObjects(); 171 | int hashCode = size(); 172 | 173 | while (e.hasMoreElements()) 174 | { 175 | Object o = getNext(e); 176 | hashCode *= 17; 177 | 178 | hashCode ^= o.hashCode(); 179 | } 180 | 181 | return hashCode; 182 | } 183 | 184 | boolean asn1Equals( 185 | DERObject o) 186 | { 187 | if (!(o instanceof ASN1Sequence)) 188 | { 189 | return false; 190 | } 191 | 192 | ASN1Sequence other = (ASN1Sequence)o; 193 | 194 | if (this.size() != other.size()) 195 | { 196 | return false; 197 | } 198 | 199 | Enumeration s1 = this.getObjects(); 200 | Enumeration s2 = other.getObjects(); 201 | 202 | while (s1.hasMoreElements()) 203 | { 204 | DEREncodable obj1 = getNext(s1); 205 | DEREncodable obj2 = getNext(s2); 206 | 207 | DERObject o1 = obj1.getDERObject(); 208 | DERObject o2 = obj2.getDERObject(); 209 | 210 | if (o1 == o2 || o1.equals(o2)) 211 | { 212 | continue; 213 | } 214 | 215 | return false; 216 | } 217 | 218 | return true; 219 | } 220 | 221 | private DEREncodable getNext(Enumeration e) 222 | { 223 | DEREncodable encObj = (DEREncodable)e.nextElement(); 224 | 225 | // unfortunately null was allowed as a substitute for DER null 226 | if (encObj == null) 227 | { 228 | return DERNull.INSTANCE; 229 | } 230 | 231 | return encObj; 232 | } 233 | 234 | protected void addObject( 235 | DEREncodable obj) 236 | { 237 | seq.addElement(obj); 238 | } 239 | 240 | abstract void encode(DEROutputStream out) 241 | throws IOException; 242 | 243 | public String toString() 244 | { 245 | return seq.toString(); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /BraintreeAndroidEncryption/src/main/java/com/braintree/org/bouncycastle/asn1/DERUTCTime.java: -------------------------------------------------------------------------------- 1 | package com.braintree.org.bouncycastle.asn1; 2 | 3 | import java.io.IOException; 4 | import java.text.ParseException; 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.SimpleTimeZone; 8 | 9 | /** 10 | * UTC time object. 11 | */ 12 | public class DERUTCTime 13 | extends ASN1Object 14 | { 15 | String time; 16 | 17 | /** 18 | * return an UTC Time from the passed in object. 19 | * 20 | * @exception IllegalArgumentException if the object cannot be converted. 21 | */ 22 | public static DERUTCTime getInstance( 23 | Object obj) 24 | { 25 | if (obj == null || obj instanceof DERUTCTime) 26 | { 27 | return (DERUTCTime)obj; 28 | } 29 | 30 | throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 31 | } 32 | 33 | /** 34 | * return an UTC Time from a tagged object. 35 | * 36 | * @param obj the tagged object holding the object we want 37 | * @param explicit true if the object is meant to be explicitly 38 | * tagged false otherwise. 39 | * @exception IllegalArgumentException if the tagged object cannot 40 | * be converted. 41 | */ 42 | public static DERUTCTime getInstance( 43 | ASN1TaggedObject obj, 44 | boolean explicit) 45 | { 46 | DERObject o = obj.getObject(); 47 | 48 | if (explicit || o instanceof DERUTCTime) 49 | { 50 | return getInstance(o); 51 | } 52 | else 53 | { 54 | return new DERUTCTime(((ASN1OctetString)o).getOctets()); 55 | } 56 | } 57 | 58 | /** 59 | * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were 60 | * never encoded. When you're creating one of these objects from scratch, that's 61 | * what you want to use, otherwise we'll try to deal with whatever gets read from 62 | * the input stream... (this is why the input format is different from the getTime() 63 | * method output). 64 | *

65 | * 66 | * @param time the time string. 67 | */ 68 | public DERUTCTime( 69 | String time) 70 | { 71 | this.time = time; 72 | try 73 | { 74 | this.getDate(); 75 | } 76 | catch (ParseException e) 77 | { 78 | throw new IllegalArgumentException("invalid date string: " + e.getMessage()); 79 | } 80 | } 81 | 82 | /** 83 | * base constructer from a java.util.date object 84 | */ 85 | public DERUTCTime( 86 | Date time) 87 | { 88 | SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); 89 | 90 | dateF.setTimeZone(new SimpleTimeZone(0,"Z")); 91 | 92 | this.time = dateF.format(time); 93 | } 94 | 95 | DERUTCTime( 96 | byte[] bytes) 97 | { 98 | // 99 | // explicitly convert to characters 100 | // 101 | char[] dateC = new char[bytes.length]; 102 | 103 | for (int i = 0; i != dateC.length; i++) 104 | { 105 | dateC[i] = (char)(bytes[i] & 0xff); 106 | } 107 | 108 | this.time = new String(dateC); 109 | } 110 | 111 | /** 112 | * return the time as a date based on whatever a 2 digit year will return. For 113 | * standardised processing use getAdjustedDate(). 114 | * 115 | * @return the resulting date 116 | * @exception ParseException if the date string cannot be parsed. 117 | */ 118 | public Date getDate() 119 | throws ParseException 120 | { 121 | SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); 122 | 123 | return dateF.parse(getTime()); 124 | } 125 | 126 | /** 127 | * return the time as an adjusted date 128 | * in the range of 1950 - 2049. 129 | * 130 | * @return a date in the range of 1950 to 2049. 131 | * @exception ParseException if the date string cannot be parsed. 132 | */ 133 | public Date getAdjustedDate() 134 | throws ParseException 135 | { 136 | SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); 137 | 138 | dateF.setTimeZone(new SimpleTimeZone(0, "Z")); 139 | 140 | return dateF.parse(getAdjustedTime()); 141 | } 142 | 143 | /** 144 | * return the time - always in the form of 145 | * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). 146 | *

147 | * Normally in a certificate we would expect "Z" rather than "GMT", 148 | * however adding the "GMT" means we can just use: 149 | *

150 |      *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
151 |      * 
152 | * To read in the time and get a date which is compatible with our local 153 | * time zone. 154 | *

155 | * Note: In some cases, due to the local date processing, this 156 | * may lead to unexpected results. If you want to stick the normal 157 | * convention of 1950 to 2049 use the getAdjustedTime() method. 158 | */ 159 | public String getTime() 160 | { 161 | // 162 | // standardise the format. 163 | // 164 | if (time.indexOf('-') < 0 && time.indexOf('+') < 0) 165 | { 166 | if (time.length() == 11) 167 | { 168 | return time.substring(0, 10) + "00GMT+00:00"; 169 | } 170 | else 171 | { 172 | return time.substring(0, 12) + "GMT+00:00"; 173 | } 174 | } 175 | else 176 | { 177 | int index = time.indexOf('-'); 178 | if (index < 0) 179 | { 180 | index = time.indexOf('+'); 181 | } 182 | String d = time; 183 | 184 | if (index == time.length() - 3) 185 | { 186 | d += "00"; 187 | } 188 | 189 | if (index == 10) 190 | { 191 | return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15); 192 | } 193 | else 194 | { 195 | return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17); 196 | } 197 | } 198 | } 199 | 200 | /** 201 | * return a time string as an adjusted date with a 4 digit year. This goes 202 | * in the range of 1950 - 2049. 203 | */ 204 | public String getAdjustedTime() 205 | { 206 | String d = this.getTime(); 207 | 208 | if (d.charAt(0) < '5') 209 | { 210 | return "20" + d; 211 | } 212 | else 213 | { 214 | return "19" + d; 215 | } 216 | } 217 | 218 | private byte[] getOctets() 219 | { 220 | char[] cs = time.toCharArray(); 221 | byte[] bs = new byte[cs.length]; 222 | 223 | for (int i = 0; i != cs.length; i++) 224 | { 225 | bs[i] = (byte)cs[i]; 226 | } 227 | 228 | return bs; 229 | } 230 | 231 | void encode( 232 | DEROutputStream out) 233 | throws IOException 234 | { 235 | out.writeEncoded(UTC_TIME, this.getOctets()); 236 | } 237 | 238 | boolean asn1Equals( 239 | DERObject o) 240 | { 241 | if (!(o instanceof DERUTCTime)) 242 | { 243 | return false; 244 | } 245 | 246 | return time.equals(((DERUTCTime)o).time); 247 | } 248 | 249 | public int hashCode() 250 | { 251 | return time.hashCode(); 252 | } 253 | 254 | public String toString() 255 | { 256 | return time; 257 | } 258 | } 259 | --------------------------------------------------------------------------------