Move common crypto classes into TextSecureLibrary.
1) Move all the crypto classes from securesms.crypto. 2) Move all the crypto storage from securesms.database.keys 3) Replace the old imported BC code with spongycastle.
This commit is contained in:
parent
2042ca6cb7
commit
b8f663b69c
232 changed files with 412 additions and 13478 deletions
BIN
library/libs/sc-light-jdk15on-1.47.0.2.jar
Normal file
BIN
library/libs/sc-light-jdk15on-1.47.0.2.jar
Normal file
Binary file not shown.
|
@ -1,9 +1,9 @@
|
|||
package textsecure;
|
||||
|
||||
option java_package = "org.thoughtcrime.securesms.encoded";
|
||||
option java_package = "org.whispersystems.textsecure.encoded";
|
||||
option java_outer_classname = "PreKeyProtos";
|
||||
|
||||
message PreKeyEntity {
|
||||
optional uint64 id = 1;
|
||||
optional bytes key = 2;
|
||||
}
|
||||
}
|
|
@ -14,13 +14,13 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
/**
|
||||
* A class for representing an identity key.
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
public class InvalidKeyException extends Exception {
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
public class InvalidMacException extends Exception {
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.util;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
public class InvalidMessageException extends Exception {
|
||||
|
|
@ -14,12 +14,12 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
import android.util.Log;
|
||||
|
|
@ -14,26 +14,25 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
|
||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.math.ec.ECCurve;
|
||||
import org.bouncycastle.math.ec.ECFieldElement;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.thoughtcrime.securesms.database.keys.LocalKeyRecord;
|
||||
import org.thoughtcrime.securesms.database.keys.PreKeyRecord;
|
||||
import org.thoughtcrime.securesms.database.keys.RemoteKeyRecord;
|
||||
import org.thoughtcrime.securesms.database.keys.SessionRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
|
||||
import org.spongycastle.crypto.generators.ECKeyPairGenerator;
|
||||
import org.spongycastle.crypto.params.ECDomainParameters;
|
||||
import org.spongycastle.crypto.params.ECKeyGenerationParameters;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.spongycastle.math.ec.ECCurve;
|
||||
import org.spongycastle.math.ec.ECFieldElement;
|
||||
import org.spongycastle.math.ec.ECPoint;
|
||||
import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
|
||||
import org.whispersystems.textsecure.storage.LocalKeyRecord;
|
||||
import org.whispersystems.textsecure.storage.RemoteKeyRecord;
|
||||
import org.whispersystems.textsecure.storage.SessionRecord;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
@ -92,7 +91,7 @@ public class KeyUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void abortSessionFor(Context context, Recipient recipient) {
|
||||
public static void abortSessionFor(Context context, CanonicalRecipientAddress recipient) {
|
||||
//XXX Obviously we should probably do something more thorough here eventually.
|
||||
Log.w("KeyUtil", "Aborting session, deleting keys...");
|
||||
LocalKeyRecord.delete(context, recipient);
|
||||
|
@ -100,7 +99,7 @@ public class KeyUtil {
|
|||
SessionRecord.delete(context, recipient);
|
||||
}
|
||||
|
||||
public static boolean isSessionFor(Context context, Recipient recipient) {
|
||||
public static boolean isSessionFor(Context context, CanonicalRecipientAddress recipient) {
|
||||
Log.w("KeyUtil", "Checking session...");
|
||||
return
|
||||
(LocalKeyRecord.hasRecord(context, recipient)) &&
|
||||
|
@ -110,13 +109,16 @@ public class KeyUtil {
|
|||
|
||||
public static boolean isIdentityKeyFor(Context context,
|
||||
MasterSecret masterSecret,
|
||||
Recipient recipient)
|
||||
CanonicalRecipientAddress recipient)
|
||||
{
|
||||
return isSessionFor(context, recipient) &&
|
||||
new SessionRecord(context, masterSecret, recipient).getIdentityKey() != null;
|
||||
}
|
||||
|
||||
public static LocalKeyRecord initializeRecordFor(Recipient recipient, Context context, MasterSecret masterSecret) {
|
||||
public static LocalKeyRecord initializeRecordFor(CanonicalRecipientAddress recipient,
|
||||
Context context,
|
||||
MasterSecret masterSecret)
|
||||
{
|
||||
Log.w("KeyUtil", "Initializing local key pairs...");
|
||||
try {
|
||||
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
@ -32,10 +32,9 @@ import javax.crypto.NoSuchPaddingException;
|
|||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.thoughtcrime.securesms.util.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
import android.util.Log;
|
||||
|
|
@ -14,14 +14,13 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* When a user first initializes TextSecure, a few secrets
|
||||
|
@ -72,7 +71,7 @@ public class MasterSecret implements Parcelable {
|
|||
this.macKey = new SecretKeySpec(macKeyBytes, "HmacSHA1");
|
||||
|
||||
// SecretKeySpec does an internal copy in its constructor.
|
||||
Arrays.fill(encryptionKeyBytes, (byte)0x00);
|
||||
Arrays.fill(encryptionKeyBytes, (byte) 0x00);
|
||||
Arrays.fill(macKeyBytes, (byte)0x00);
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -23,7 +23,7 @@ import java.util.Arrays;
|
|||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
import android.util.Log;
|
||||
|
|
@ -1,16 +1,15 @@
|
|||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
public class PreKeyPair {
|
||||
|
||||
private final MasterCipher masterCipher;
|
||||
private final MasterCipher masterCipher;
|
||||
private final ECPrivateKeyParameters privateKey;
|
||||
private final ECPublicKeyParameters publicKey;
|
||||
private final ECPublicKeyParameters publicKey;
|
||||
|
||||
public PreKeyPair(MasterSecret masterSecret, AsymmetricCipherKeyPair keyPair) {
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
|
@ -1,13 +1,13 @@
|
|||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import org.thoughtcrime.securesms.database.keys.InvalidKeyIdException;
|
||||
import org.thoughtcrime.securesms.database.keys.PreKeyRecord;
|
||||
import org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity;
|
||||
import org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity;
|
||||
import org.whispersystems.textsecure.push.PreKeyList;
|
||||
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.storage.PreKeyRecord;
|
||||
import org.whispersystems.textsecure.util.Base64;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -26,7 +26,7 @@ public class PreKeyUtil {
|
|||
|
||||
for (int i=0;i<BATCH_SIZE;i++) {
|
||||
Log.w("PreKeyUtil", "Generating PreKey: " + (preKeyIdOffset + i));
|
||||
PreKeyPair keyPair = new PreKeyPair(masterSecret, KeyUtil.generateKeyPair());
|
||||
PreKeyPair keyPair = new PreKeyPair(masterSecret, KeyUtil.generateKeyPair());
|
||||
PreKeyRecord record = new PreKeyRecord(context, masterSecret, preKeyIdOffset + i, keyPair);
|
||||
|
||||
record.save();
|
|
@ -14,12 +14,12 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
|
||||
import java.security.MessageDigest;
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
public interface SerializableKey {
|
||||
public byte[] serialize();
|
|
@ -14,14 +14,22 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.spongycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.spongycastle.crypto.agreement.ECDHBasicAgreement;
|
||||
import org.spongycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.whispersystems.textsecure.protocol.Message;
|
||||
import org.whispersystems.textsecure.storage.CanonicalRecipientAddress;
|
||||
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
|
||||
import org.whispersystems.textsecure.storage.LocalKeyRecord;
|
||||
import org.whispersystems.textsecure.storage.RemoteKeyRecord;
|
||||
import org.whispersystems.textsecure.storage.SessionKey;
|
||||
import org.whispersystems.textsecure.storage.SessionRecord;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
|
@ -29,21 +37,12 @@ import javax.crypto.IllegalBlockSizeException;
|
|||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.thoughtcrime.securesms.database.keys.InvalidKeyIdException;
|
||||
import org.thoughtcrime.securesms.database.keys.LocalKeyRecord;
|
||||
import org.thoughtcrime.securesms.database.keys.RemoteKeyRecord;
|
||||
import org.thoughtcrime.securesms.database.keys.SessionKey;
|
||||
import org.thoughtcrime.securesms.database.keys.SessionRecord;
|
||||
import org.thoughtcrime.securesms.protocol.Message;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* This is where the session encryption magic happens. Implements a compressed version of the OTR protocol.
|
||||
|
@ -64,10 +63,10 @@ public class SessionCipher {
|
|||
private final LocalKeyRecord localRecord;
|
||||
private final RemoteKeyRecord remoteRecord;
|
||||
private final SessionRecord sessionRecord;
|
||||
private final MasterSecret masterSecret;
|
||||
private final MasterSecret masterSecret;
|
||||
private final TransportDetails transportDetails;
|
||||
|
||||
public SessionCipher(Context context, MasterSecret masterSecret, Recipient recipient, TransportDetails transportDetails) {
|
||||
public SessionCipher(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient, TransportDetails transportDetails) {
|
||||
Log.w("SessionCipher", "Constructing session cipher...");
|
||||
this.masterSecret = masterSecret;
|
||||
this.localRecord = new LocalKeyRecord(context, masterSecret, recipient);
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.crypto;
|
||||
package org.whispersystems.textsecure.crypto;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: PreKeyEntity.proto
|
||||
|
||||
package org.thoughtcrime.securesms.encoded;
|
||||
package org.whispersystems.textsecure.encoded;
|
||||
|
||||
public final class PreKeyProtos {
|
||||
private PreKeyProtos() {}
|
||||
|
@ -39,12 +39,12 @@ public final class PreKeyProtos {
|
|||
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.thoughtcrime.securesms.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_descriptor;
|
||||
return org.whispersystems.textsecure.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.thoughtcrime.securesms.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_fieldAccessorTable;
|
||||
return org.whispersystems.textsecure.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_fieldAccessorTable;
|
||||
}
|
||||
|
||||
private int bitField0_;
|
||||
|
@ -119,41 +119,41 @@ public final class PreKeyProtos {
|
|||
return super.writeReplace();
|
||||
}
|
||||
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
com.google.protobuf.ByteString data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
com.google.protobuf.ByteString data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(byte[] data)
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(byte[] data)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data).buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
byte[] data,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
return newBuilder().mergeFrom(data, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input, extensionRegistry)
|
||||
.buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseDelimitedFrom(java.io.InputStream input)
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseDelimitedFrom(java.io.InputStream input)
|
||||
throws java.io.IOException {
|
||||
Builder builder = newBuilder();
|
||||
if (builder.mergeDelimitedFrom(input)) {
|
||||
|
@ -162,7 +162,7 @@ public final class PreKeyProtos {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseDelimitedFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseDelimitedFrom(
|
||||
java.io.InputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
|
@ -173,12 +173,12 @@ public final class PreKeyProtos {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
com.google.protobuf.CodedInputStream input)
|
||||
throws java.io.IOException {
|
||||
return newBuilder().mergeFrom(input).buildParsed();
|
||||
}
|
||||
public static org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
public static org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity parseFrom(
|
||||
com.google.protobuf.CodedInputStream input,
|
||||
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
|
||||
throws java.io.IOException {
|
||||
|
@ -188,7 +188,7 @@ public final class PreKeyProtos {
|
|||
|
||||
public static Builder newBuilder() { return Builder.create(); }
|
||||
public Builder newBuilderForType() { return newBuilder(); }
|
||||
public static Builder newBuilder(org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity prototype) {
|
||||
public static Builder newBuilder(org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity prototype) {
|
||||
return newBuilder().mergeFrom(prototype);
|
||||
}
|
||||
public Builder toBuilder() { return newBuilder(this); }
|
||||
|
@ -201,18 +201,18 @@ public final class PreKeyProtos {
|
|||
}
|
||||
public static final class Builder extends
|
||||
com.google.protobuf.GeneratedMessage.Builder<Builder>
|
||||
implements org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntityOrBuilder {
|
||||
implements org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntityOrBuilder {
|
||||
public static final com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptor() {
|
||||
return org.thoughtcrime.securesms.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_descriptor;
|
||||
return org.whispersystems.textsecure.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_descriptor;
|
||||
}
|
||||
|
||||
protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
|
||||
internalGetFieldAccessorTable() {
|
||||
return org.thoughtcrime.securesms.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_fieldAccessorTable;
|
||||
return org.whispersystems.textsecure.encoded.PreKeyProtos.internal_static_textsecure_PreKeyEntity_fieldAccessorTable;
|
||||
}
|
||||
|
||||
// Construct using org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity.newBuilder()
|
||||
// Construct using org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity.newBuilder()
|
||||
private Builder() {
|
||||
maybeForceBuilderInitialization();
|
||||
}
|
||||
|
@ -244,24 +244,24 @@ public final class PreKeyProtos {
|
|||
|
||||
public com.google.protobuf.Descriptors.Descriptor
|
||||
getDescriptorForType() {
|
||||
return org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity.getDescriptor();
|
||||
return org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity.getDescriptor();
|
||||
}
|
||||
|
||||
public org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity getDefaultInstanceForType() {
|
||||
return org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity.getDefaultInstance();
|
||||
public org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity getDefaultInstanceForType() {
|
||||
return org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity.getDefaultInstance();
|
||||
}
|
||||
|
||||
public org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity build() {
|
||||
org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity result = buildPartial();
|
||||
public org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity build() {
|
||||
org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity buildParsed()
|
||||
private org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity buildParsed()
|
||||
throws com.google.protobuf.InvalidProtocolBufferException {
|
||||
org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity result = buildPartial();
|
||||
org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity result = buildPartial();
|
||||
if (!result.isInitialized()) {
|
||||
throw newUninitializedMessageException(
|
||||
result).asInvalidProtocolBufferException();
|
||||
|
@ -269,8 +269,8 @@ public final class PreKeyProtos {
|
|||
return result;
|
||||
}
|
||||
|
||||
public org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity buildPartial() {
|
||||
org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity result = new org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity(this);
|
||||
public org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity buildPartial() {
|
||||
org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity result = new org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity(this);
|
||||
int from_bitField0_ = bitField0_;
|
||||
int to_bitField0_ = 0;
|
||||
if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
|
||||
|
@ -287,16 +287,16 @@ public final class PreKeyProtos {
|
|||
}
|
||||
|
||||
public Builder mergeFrom(com.google.protobuf.Message other) {
|
||||
if (other instanceof org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity) {
|
||||
return mergeFrom((org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity)other);
|
||||
if (other instanceof org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity) {
|
||||
return mergeFrom((org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity)other);
|
||||
} else {
|
||||
super.mergeFrom(other);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder mergeFrom(org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity other) {
|
||||
if (other == org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity.getDefaultInstance()) return this;
|
||||
public Builder mergeFrom(org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity other) {
|
||||
if (other == org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity.getDefaultInstance()) return this;
|
||||
if (other.hasId()) {
|
||||
setId(other.getId());
|
||||
}
|
||||
|
@ -421,9 +421,9 @@ public final class PreKeyProtos {
|
|||
static {
|
||||
java.lang.String[] descriptorData = {
|
||||
"\n\022PreKeyEntity.proto\022\ntextsecure\"\'\n\014PreK" +
|
||||
"eyEntity\022\n\n\002id\030\001 \001(\004\022\013\n\003key\030\002 \001(\014B2\n\"org" +
|
||||
".thoughtcrime.securesms.encodedB\014PreKeyP" +
|
||||
"rotos"
|
||||
"eyEntity\022\n\n\002id\030\001 \001(\004\022\013\n\003key\030\002 \001(\014B5\n%org" +
|
||||
".whispersystems.textsecure.encodedB\014PreK" +
|
||||
"eyProtos"
|
||||
};
|
||||
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
|
||||
|
@ -436,8 +436,8 @@ public final class PreKeyProtos {
|
|||
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
|
||||
internal_static_textsecure_PreKeyEntity_descriptor,
|
||||
new java.lang.String[] { "Id", "Key", },
|
||||
org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity.class,
|
||||
org.thoughtcrime.securesms.encoded.PreKeyProtos.PreKeyEntity.Builder.class);
|
||||
org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity.class,
|
||||
org.whispersystems.textsecure.encoded.PreKeyProtos.PreKeyEntity.Builder.class);
|
||||
return null;
|
||||
}
|
||||
};
|
|
@ -14,13 +14,13 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.protocol;
|
||||
package org.whispersystems.textsecure.protocol;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.InvalidMessageException;
|
||||
import org.thoughtcrime.securesms.crypto.PublicKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.InvalidMessageException;
|
||||
import org.whispersystems.textsecure.crypto.PublicKey;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
|
@ -0,0 +1,7 @@
|
|||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
public interface CanonicalRecipientAddress {
|
||||
public long getCanonicalAddress(Context context);
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
public class InvalidKeyIdException extends Exception {
|
||||
|
|
@ -14,18 +14,16 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.KeyPair;
|
||||
import org.thoughtcrime.securesms.crypto.KeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.KeyPair;
|
||||
import org.whispersystems.textsecure.crypto.KeyUtil;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -43,24 +41,24 @@ public class LocalKeyRecord extends Record {
|
|||
private final MasterCipher masterCipher;
|
||||
private final MasterSecret masterSecret;
|
||||
|
||||
public LocalKeyRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
||||
public LocalKeyRecord(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient) {
|
||||
super(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
this.masterSecret = masterSecret;
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
||||
loadData();
|
||||
}
|
||||
|
||||
public static boolean hasRecord(Context context, Recipient recipient) {
|
||||
public static boolean hasRecord(Context context, CanonicalRecipientAddress recipient) {
|
||||
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
||||
return Record.hasRecord(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
public static void delete(Context context, Recipient recipient) {
|
||||
public static void delete(Context context, CanonicalRecipientAddress recipient) {
|
||||
Record.delete(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
||||
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "-local";
|
||||
private static String getFileNameForRecipient(Context context, CanonicalRecipientAddress recipient) {
|
||||
return recipient.getCanonicalAddress(context) + "-local";
|
||||
}
|
||||
|
||||
public void advanceKeyIfNecessary(int keyId) {
|
|
@ -1,12 +1,11 @@
|
|||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.PreKeyPair;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.PreKeyPair;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -19,7 +18,6 @@ public class PreKeyRecord extends Record {
|
|||
private static final Object FILE_LOCK = new Object();
|
||||
private static final int CURRENT_VERSION_MARKER = 1;
|
||||
|
||||
private final MasterCipher masterCipher;
|
||||
private final MasterSecret masterSecret;
|
||||
|
||||
private PreKeyPair keyPair;
|
||||
|
@ -32,7 +30,6 @@ public class PreKeyRecord extends Record {
|
|||
|
||||
this.id = id;
|
||||
this.masterSecret = masterSecret;
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
@ -44,7 +41,6 @@ public class PreKeyRecord extends Record {
|
|||
this.id = id;
|
||||
this.keyPair = keyPair;
|
||||
this.masterSecret = masterSecret;
|
||||
this.masterCipher = new MasterCipher(masterSecret);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
|
@ -95,7 +91,7 @@ public class PreKeyRecord extends Record {
|
|||
return;
|
||||
}
|
||||
|
||||
keyPair = readKeyPair(in, masterCipher);
|
||||
keyPair = readKeyPair(in);
|
||||
in.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.w("PreKeyRecord", e);
|
||||
|
@ -115,7 +111,7 @@ public class PreKeyRecord extends Record {
|
|||
writeBlob(serialized, out);
|
||||
}
|
||||
|
||||
private PreKeyPair readKeyPair(FileInputStream in, MasterCipher masterCipher)
|
||||
private PreKeyPair readKeyPair(FileInputStream in)
|
||||
throws IOException, InvalidKeyException
|
||||
{
|
||||
byte[] keyPairBytes = readBlob(in);
|
|
@ -14,13 +14,10 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.KeyPair;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
|
||||
import java.io.File;
|
|
@ -14,18 +14,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.PublicKey;
|
||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
||||
import org.thoughtcrime.securesms.database.keys.InvalidKeyIdException;
|
||||
import org.thoughtcrime.securesms.database.keys.Record;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.PublicKey;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -46,22 +42,22 @@ public class RemoteKeyRecord extends Record {
|
|||
private PublicKey remoteKeyCurrent;
|
||||
private PublicKey remoteKeyLast;
|
||||
|
||||
public RemoteKeyRecord(Context context, Recipient recipient) {
|
||||
public RemoteKeyRecord(Context context, CanonicalRecipientAddress recipient) {
|
||||
super(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
loadData();
|
||||
}
|
||||
|
||||
public static void delete(Context context, Recipient recipient) {
|
||||
Record.delete(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
public static void delete(Context context, CanonicalRecipientAddress recipient) {
|
||||
delete(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
public static boolean hasRecord(Context context, Recipient recipient) {
|
||||
public static boolean hasRecord(Context context, CanonicalRecipientAddress recipient) {
|
||||
Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient));
|
||||
return Record.hasRecord(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
return hasRecord(context, SESSIONS_DIRECTORY, getFileNameForRecipient(context, recipient));
|
||||
}
|
||||
|
||||
private static String getFileNameForRecipient(Context context, Recipient recipient) {
|
||||
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "-remote";
|
||||
private static String getFileNameForRecipient(Context context, CanonicalRecipientAddress recipient) {
|
||||
return recipient.getCanonicalAddress(context) + "-remote";
|
||||
}
|
||||
|
||||
public void updateCurrentRemoteKey(PublicKey remoteKey) {
|
|
@ -14,13 +14,13 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.SessionCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterCipher;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipher;
|
||||
import org.whispersystems.textsecure.util.Conversions;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
|
@ -14,16 +14,14 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.database.keys;
|
||||
package org.whispersystems.textsecure.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKey;
|
||||
import org.thoughtcrime.securesms.crypto.InvalidKeyException;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.whispersystems.textsecure.crypto.IdentityKey;
|
||||
import org.whispersystems.textsecure.crypto.InvalidKeyException;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -53,7 +51,7 @@ public class SessionRecord extends Record {
|
|||
|
||||
private final MasterSecret masterSecret;
|
||||
|
||||
public SessionRecord(Context context, MasterSecret masterSecret, Recipient recipient) {
|
||||
public SessionRecord(Context context, MasterSecret masterSecret, CanonicalRecipientAddress recipient) {
|
||||
this(context, masterSecret, getRecipientId(context, recipient));
|
||||
}
|
||||
|
||||
|
@ -64,17 +62,17 @@ public class SessionRecord extends Record {
|
|||
loadData();
|
||||
}
|
||||
|
||||
public static void delete(Context context, Recipient recipient) {
|
||||
Record.delete(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
|
||||
public static void delete(Context context, CanonicalRecipientAddress recipient) {
|
||||
delete(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
|
||||
}
|
||||
|
||||
public static boolean hasSession(Context context, Recipient recipient) {
|
||||
public static boolean hasSession(Context context, CanonicalRecipientAddress recipient) {
|
||||
Log.w("LocalKeyRecord", "Checking: " + getRecipientId(context, recipient));
|
||||
return Record.hasRecord(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
|
||||
return hasRecord(context, SESSIONS_DIRECTORY, getRecipientId(context, recipient)+"");
|
||||
}
|
||||
|
||||
private static long getRecipientId(Context context, Recipient recipient) {
|
||||
return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber());
|
||||
private static long getRecipientId(Context context, CanonicalRecipientAddress recipient) {
|
||||
return recipient.getCanonicalAddress(context);
|
||||
}
|
||||
|
||||
public void setSessionKey(SessionKey sessionKeyRecord) {
|
|
@ -14,7 +14,7 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms.util;
|
||||
package org.whispersystems.textsecure.util;
|
||||
|
||||
/**
|
||||
* Utility for generating hex dumps.
|
|
@ -16,6 +16,35 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
|
||||
public class Util {
|
||||
|
||||
public static byte[] combine(byte[] one, byte[] two) {
|
||||
byte[] combined = new byte[one.length + two.length];
|
||||
System.arraycopy(one, 0, combined, 0, one.length);
|
||||
System.arraycopy(two, 0, combined, one.length, two.length);
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
public static byte[] combine(byte[] one, byte[] two, byte[] three) {
|
||||
byte[] combined = new byte[one.length + two.length + three.length];
|
||||
System.arraycopy(one, 0, combined, 0, one.length);
|
||||
System.arraycopy(two, 0, combined, one.length, two.length);
|
||||
System.arraycopy(three, 0, combined, one.length + two.length, three.length);
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
public static byte[] combine(byte[] one, byte[] two, byte[] three, byte[] four) {
|
||||
byte[] combined = new byte[one.length + two.length + three.length + four.length];
|
||||
System.arraycopy(one, 0, combined, 0, one.length);
|
||||
System.arraycopy(two, 0, combined, one.length, two.length);
|
||||
System.arraycopy(three, 0, combined, one.length + two.length, three.length);
|
||||
System.arraycopy(four, 0, combined, one.length + two.length + three.length, four.length);
|
||||
|
||||
return combined;
|
||||
|
||||
}
|
||||
|
||||
public static boolean isEmpty(String value) {
|
||||
return value == null || value.trim().length() == 0;
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* a holding class for public/private parameter pairs.
|
||||
*/
|
||||
public class AsymmetricCipherKeyPair
|
||||
{
|
||||
private CipherParameters publicParam;
|
||||
private CipherParameters privateParam;
|
||||
|
||||
/**
|
||||
* basic constructor.
|
||||
*
|
||||
* @param publicParam a public key parameters object.
|
||||
* @param privateParam the corresponding private key parameters.
|
||||
*/
|
||||
public AsymmetricCipherKeyPair(
|
||||
CipherParameters publicParam,
|
||||
CipherParameters privateParam)
|
||||
{
|
||||
this.publicParam = publicParam;
|
||||
this.privateParam = privateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the public key parameters.
|
||||
*
|
||||
* @return the public key parameters.
|
||||
*/
|
||||
public CipherParameters getPublic()
|
||||
{
|
||||
return publicParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the private key parameters.
|
||||
*
|
||||
* @return the private key parameters.
|
||||
*/
|
||||
public CipherParameters getPrivate()
|
||||
{
|
||||
return privateParam;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* interface that a public/private key pair generator should conform to.
|
||||
*/
|
||||
public interface AsymmetricCipherKeyPairGenerator
|
||||
{
|
||||
/**
|
||||
* intialise the key pair generator.
|
||||
*
|
||||
* @param param the parameters the key pair is to be initialised with.
|
||||
*/
|
||||
public void init(KeyGenerationParameters param);
|
||||
|
||||
/**
|
||||
* return an AsymmetricCipherKeyPair containing the generated keys.
|
||||
*
|
||||
* @return an AsymmetricCipherKeyPair containing the generated keys.
|
||||
*/
|
||||
public AsymmetricCipherKeyPair generateKeyPair();
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package org.bouncycastle.crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* The basic interface that basic Diffie-Hellman implementations
|
||||
* conforms to.
|
||||
*/
|
||||
public interface BasicAgreement
|
||||
{
|
||||
/**
|
||||
* initialise the agreement engine.
|
||||
*/
|
||||
public void init(CipherParameters param);
|
||||
|
||||
/**
|
||||
* given a public key from a given party calculate the next
|
||||
* message in the agreement sequence.
|
||||
*/
|
||||
public BigInteger calculateAgreement(CipherParameters pubKey);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package org.bouncycastle.crypto;
|
||||
|
||||
/**
|
||||
* all parameter classes implement this.
|
||||
*/
|
||||
public interface CipherParameters
|
||||
{
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package org.bouncycastle.crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* interface for classes implementing algorithms modeled similar to the Digital Signature Alorithm.
|
||||
*/
|
||||
public interface DSA
|
||||
{
|
||||
/**
|
||||
* initialise the signer for signature generation or signature
|
||||
* verification.
|
||||
*
|
||||
* @param forSigning true if we are generating a signature, false
|
||||
* otherwise.
|
||||
* @param param key parameters for signature generation.
|
||||
*/
|
||||
public void init(boolean forSigning, CipherParameters param);
|
||||
|
||||
/**
|
||||
* sign the passed in message (usually the output of a hash function).
|
||||
*
|
||||
* @param message the message to be signed.
|
||||
* @return two big integers representing the r and s values respectively.
|
||||
*/
|
||||
public BigInteger[] generateSignature(byte[] message);
|
||||
|
||||
/**
|
||||
* verify the message message against the signature values r and s.
|
||||
*
|
||||
* @param message the message that was supposed to have been signed.
|
||||
* @param r the r signature value.
|
||||
* @param s the s signature value.
|
||||
*/
|
||||
public boolean verifySignature(byte[] message, BigInteger r, BigInteger s);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package org.bouncycastle.crypto;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* The base class for parameters to key generators.
|
||||
*/
|
||||
public class KeyGenerationParameters
|
||||
{
|
||||
private SecureRandom random;
|
||||
private int strength;
|
||||
|
||||
/**
|
||||
* initialise the generator with a source of randomness
|
||||
* and a strength (in bits).
|
||||
*
|
||||
* @param random the random byte source.
|
||||
* @param strength the size, in bits, of the keys we want to produce.
|
||||
*/
|
||||
public KeyGenerationParameters(
|
||||
SecureRandom random,
|
||||
int strength)
|
||||
{
|
||||
this.random = random;
|
||||
this.strength = strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the random source associated with this
|
||||
* generator.
|
||||
*
|
||||
* @return the generators random source.
|
||||
*/
|
||||
public SecureRandom getRandom()
|
||||
{
|
||||
return random;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the bit strength for keys produced by this generator,
|
||||
*
|
||||
* @return the strength of the keys this generator produces (in bits).
|
||||
*/
|
||||
public int getStrength()
|
||||
{
|
||||
return strength;
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package org.bouncycastle.crypto.agreement;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
import org.bouncycastle.crypto.BasicAgreement;
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
|
||||
/**
|
||||
* P1363 7.2.1 ECSVDP-DH
|
||||
*
|
||||
* ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
|
||||
* Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
|
||||
* and [Kob87]. This primitive derives a shared secret value from one
|
||||
* party's private key and another party's public key, where both have
|
||||
* the same set of EC domain parameters. If two parties correctly
|
||||
* execute this primitive, they will produce the same output. This
|
||||
* primitive can be invoked by a scheme to derive a shared secret key;
|
||||
* specifically, it may be used with the schemes ECKAS-DH1 and
|
||||
* DL/ECKAS-DH2. It assumes that the input keys are valid (see also
|
||||
* Section 7.2.2).
|
||||
*/
|
||||
public class ECDHBasicAgreement
|
||||
implements BasicAgreement
|
||||
{
|
||||
private ECPrivateKeyParameters key;
|
||||
|
||||
public void init(
|
||||
CipherParameters key)
|
||||
{
|
||||
this.key = (ECPrivateKeyParameters)key;
|
||||
}
|
||||
|
||||
public BigInteger calculateAgreement(
|
||||
CipherParameters pubKey)
|
||||
{
|
||||
ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
|
||||
ECPoint P = pub.getQ().multiply(key.getD());
|
||||
|
||||
// if (p.isInfinity()) throw new RuntimeException("d*Q == infinity");
|
||||
|
||||
return P.getX().toBigInteger();
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package org.bouncycastle.crypto.generators;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.KeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.math.ec.ECConstants;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
public class ECKeyPairGenerator
|
||||
implements AsymmetricCipherKeyPairGenerator, ECConstants
|
||||
{
|
||||
ECDomainParameters params;
|
||||
SecureRandom random;
|
||||
|
||||
public void init(
|
||||
KeyGenerationParameters param)
|
||||
{
|
||||
ECKeyGenerationParameters ecP = (ECKeyGenerationParameters)param;
|
||||
|
||||
this.random = ecP.getRandom();
|
||||
this.params = ecP.getDomainParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the domain parameters this routine generates an EC key
|
||||
* pair in accordance with X9.62 section 5.2.1 pages 26, 27.
|
||||
*/
|
||||
public AsymmetricCipherKeyPair generateKeyPair()
|
||||
{
|
||||
BigInteger n = params.getN();
|
||||
int nBitLength = n.bitLength();
|
||||
BigInteger d;
|
||||
|
||||
do
|
||||
{
|
||||
d = new BigInteger(nBitLength, random);
|
||||
}
|
||||
while (d.equals(ZERO) || (d.compareTo(n) >= 0));
|
||||
|
||||
ECPoint Q = params.getG().multiply(d);
|
||||
|
||||
return new AsymmetricCipherKeyPair(
|
||||
new ECPublicKeyParameters(Q, params),
|
||||
new ECPrivateKeyParameters(d, params));
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
|
||||
public class AsymmetricKeyParameter
|
||||
implements CipherParameters
|
||||
{
|
||||
boolean privateKey;
|
||||
|
||||
public AsymmetricKeyParameter(
|
||||
boolean privateKey)
|
||||
{
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
public boolean isPrivate()
|
||||
{
|
||||
return privateKey;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.math.ec.ECConstants;
|
||||
import org.bouncycastle.math.ec.ECCurve;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
public class ECDomainParameters
|
||||
implements ECConstants
|
||||
{
|
||||
ECCurve curve;
|
||||
byte[] seed;
|
||||
ECPoint G;
|
||||
BigInteger n;
|
||||
BigInteger h;
|
||||
|
||||
public ECDomainParameters(
|
||||
ECCurve curve,
|
||||
ECPoint G,
|
||||
BigInteger n)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.G = G;
|
||||
this.n = n;
|
||||
this.h = ONE;
|
||||
this.seed = null;
|
||||
}
|
||||
|
||||
public ECDomainParameters(
|
||||
ECCurve curve,
|
||||
ECPoint G,
|
||||
BigInteger n,
|
||||
BigInteger h)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.G = G;
|
||||
this.n = n;
|
||||
this.h = h;
|
||||
this.seed = null;
|
||||
}
|
||||
|
||||
public ECDomainParameters(
|
||||
ECCurve curve,
|
||||
ECPoint G,
|
||||
BigInteger n,
|
||||
BigInteger h,
|
||||
byte[] seed)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.G = G;
|
||||
this.n = n;
|
||||
this.h = h;
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
public ECCurve getCurve()
|
||||
{
|
||||
return curve;
|
||||
}
|
||||
|
||||
public ECPoint getG()
|
||||
{
|
||||
return G;
|
||||
}
|
||||
|
||||
public BigInteger getN()
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
public BigInteger getH()
|
||||
{
|
||||
return h;
|
||||
}
|
||||
|
||||
public byte[] getSeed()
|
||||
{
|
||||
return seed;
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import org.bouncycastle.crypto.KeyGenerationParameters;
|
||||
|
||||
public class ECKeyGenerationParameters
|
||||
extends KeyGenerationParameters
|
||||
{
|
||||
private ECDomainParameters domainParams;
|
||||
|
||||
public ECKeyGenerationParameters(
|
||||
ECDomainParameters domainParams,
|
||||
SecureRandom random)
|
||||
{
|
||||
super(random, domainParams.getN().bitLength());
|
||||
|
||||
this.domainParams = domainParams;
|
||||
}
|
||||
|
||||
public ECDomainParameters getDomainParameters()
|
||||
{
|
||||
return domainParams;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
public class ECKeyParameters
|
||||
extends AsymmetricKeyParameter
|
||||
{
|
||||
ECDomainParameters params;
|
||||
|
||||
protected ECKeyParameters(
|
||||
boolean isPrivate,
|
||||
ECDomainParameters params)
|
||||
{
|
||||
super(isPrivate);
|
||||
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public ECDomainParameters getParameters()
|
||||
{
|
||||
return params;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class ECPrivateKeyParameters
|
||||
extends ECKeyParameters
|
||||
{
|
||||
BigInteger d;
|
||||
|
||||
public ECPrivateKeyParameters(
|
||||
BigInteger d,
|
||||
ECDomainParameters params)
|
||||
{
|
||||
super(true, params);
|
||||
this.d = d;
|
||||
}
|
||||
|
||||
public BigInteger getD()
|
||||
{
|
||||
return d;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
public class ECPublicKeyParameters
|
||||
extends ECKeyParameters
|
||||
{
|
||||
ECPoint Q;
|
||||
|
||||
public ECPublicKeyParameters(
|
||||
ECPoint Q,
|
||||
ECDomainParameters params)
|
||||
{
|
||||
super(false, params);
|
||||
this.Q = Q;
|
||||
}
|
||||
|
||||
public ECPoint getQ()
|
||||
{
|
||||
return Q;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package org.bouncycastle.crypto.params;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class ParametersWithRandom
|
||||
implements CipherParameters
|
||||
{
|
||||
private SecureRandom random;
|
||||
private CipherParameters parameters;
|
||||
|
||||
public ParametersWithRandom(
|
||||
CipherParameters parameters,
|
||||
SecureRandom random)
|
||||
{
|
||||
this.random = random;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public ParametersWithRandom(
|
||||
CipherParameters parameters)
|
||||
{
|
||||
this(parameters, new SecureRandom());
|
||||
}
|
||||
|
||||
public SecureRandom getRandom()
|
||||
{
|
||||
return random;
|
||||
}
|
||||
|
||||
public CipherParameters getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
package org.bouncycastle.crypto.signers;
|
||||
|
||||
import org.bouncycastle.crypto.CipherParameters;
|
||||
import org.bouncycastle.crypto.DSA;
|
||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ParametersWithRandom;
|
||||
import org.bouncycastle.math.ec.ECAlgorithms;
|
||||
import org.bouncycastle.math.ec.ECConstants;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* EC-DSA as described in X9.62
|
||||
*/
|
||||
public class ECDSASigner
|
||||
implements ECConstants, DSA
|
||||
{
|
||||
ECKeyParameters key;
|
||||
|
||||
SecureRandom random;
|
||||
|
||||
public void init(
|
||||
boolean forSigning,
|
||||
CipherParameters param)
|
||||
{
|
||||
if (forSigning)
|
||||
{
|
||||
if (param instanceof ParametersWithRandom)
|
||||
{
|
||||
ParametersWithRandom rParam = (ParametersWithRandom)param;
|
||||
|
||||
this.random = rParam.getRandom();
|
||||
this.key = (ECPrivateKeyParameters)rParam.getParameters();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.random = new SecureRandom();
|
||||
this.key = (ECPrivateKeyParameters)param;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.key = (ECPublicKeyParameters)param;
|
||||
}
|
||||
}
|
||||
|
||||
// 5.3 pg 28
|
||||
/**
|
||||
* generate a signature for the given message using the key we were
|
||||
* initialised with. For conventional DSA the message should be a SHA-1
|
||||
* hash of the message of interest.
|
||||
*
|
||||
* @param message the message that will be verified later.
|
||||
*/
|
||||
public BigInteger[] generateSignature(
|
||||
byte[] message)
|
||||
{
|
||||
BigInteger n = key.getParameters().getN();
|
||||
BigInteger e = calculateE(n, message);
|
||||
BigInteger r = null;
|
||||
BigInteger s = null;
|
||||
|
||||
// 5.3.2
|
||||
do // generate s
|
||||
{
|
||||
BigInteger k = null;
|
||||
int nBitLength = n.bitLength();
|
||||
|
||||
do // generate r
|
||||
{
|
||||
do
|
||||
{
|
||||
k = new BigInteger(nBitLength, random);
|
||||
}
|
||||
while (k.equals(ZERO));
|
||||
|
||||
ECPoint p = key.getParameters().getG().multiply(k);
|
||||
|
||||
// 5.3.3
|
||||
BigInteger x = p.getX().toBigInteger();
|
||||
|
||||
r = x.mod(n);
|
||||
}
|
||||
while (r.equals(ZERO));
|
||||
|
||||
BigInteger d = ((ECPrivateKeyParameters)key).getD();
|
||||
|
||||
s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
|
||||
}
|
||||
while (s.equals(ZERO));
|
||||
|
||||
BigInteger[] res = new BigInteger[2];
|
||||
|
||||
res[0] = r;
|
||||
res[1] = s;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// 5.4 pg 29
|
||||
/**
|
||||
* return true if the value r and s represent a DSA signature for
|
||||
* the passed in message (for standard DSA the message should be
|
||||
* a SHA-1 hash of the real message to be verified).
|
||||
*/
|
||||
public boolean verifySignature(
|
||||
byte[] message,
|
||||
BigInteger r,
|
||||
BigInteger s)
|
||||
{
|
||||
BigInteger n = key.getParameters().getN();
|
||||
BigInteger e = calculateE(n, message);
|
||||
|
||||
// r in the range [1,n-1]
|
||||
if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// s in the range [1,n-1]
|
||||
if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BigInteger c = s.modInverse(n);
|
||||
|
||||
BigInteger u1 = e.multiply(c).mod(n);
|
||||
BigInteger u2 = r.multiply(c).mod(n);
|
||||
|
||||
ECPoint G = key.getParameters().getG();
|
||||
ECPoint Q = ((ECPublicKeyParameters)key).getQ();
|
||||
|
||||
ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2);
|
||||
|
||||
BigInteger v = point.getX().toBigInteger().mod(n);
|
||||
|
||||
return v.equals(r);
|
||||
}
|
||||
|
||||
private BigInteger calculateE(BigInteger n, byte[] message)
|
||||
{
|
||||
if (n.bitLength() > message.length * 8)
|
||||
{
|
||||
return new BigInteger(1, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
int messageBitLength = message.length * 8;
|
||||
BigInteger trunc = new BigInteger(1, message);
|
||||
|
||||
if (messageBitLength - n.bitLength() > 0)
|
||||
{
|
||||
trunc = trunc.shiftRight(messageBitLength - n.bitLength());
|
||||
}
|
||||
|
||||
return trunc;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class ECAlgorithms
|
||||
{
|
||||
public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
|
||||
ECPoint Q, BigInteger b)
|
||||
{
|
||||
ECCurve c = P.getCurve();
|
||||
if (!c.equals(Q.getCurve()))
|
||||
{
|
||||
throw new IllegalArgumentException("P and Q must be on same curve");
|
||||
}
|
||||
|
||||
// TODO Add special case back in when WTNAF is enabled
|
||||
// // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
|
||||
// if (c instanceof ECCurve.F2m)
|
||||
// {
|
||||
// ECCurve.F2m f2mCurve = (ECCurve.F2m) c;
|
||||
// if (f2mCurve.isKoblitz())
|
||||
// {
|
||||
// return P.multiply(a).add(Q.multiply(b));
|
||||
// }
|
||||
// }
|
||||
|
||||
return implShamirsTrick(P, a, Q, b);
|
||||
}
|
||||
|
||||
/*
|
||||
* "Shamir's Trick", originally due to E. G. Straus
|
||||
* (Addition chains of vectors. American Mathematical Monthly,
|
||||
* 71(7):806-808, Aug./Sept. 1964)
|
||||
* <pre>
|
||||
* Input: The points P, Q, scalar k = (km?, ... , k1, k0)
|
||||
* and scalar l = (lm?, ... , l1, l0).
|
||||
* Output: R = k * P + l * Q.
|
||||
* 1: Z <- P + Q
|
||||
* 2: R <- O
|
||||
* 3: for i from m-1 down to 0 do
|
||||
* 4: R <- R + R {point doubling}
|
||||
* 5: if (ki = 1) and (li = 0) then R <- R + P end if
|
||||
* 6: if (ki = 0) and (li = 1) then R <- R + Q end if
|
||||
* 7: if (ki = 1) and (li = 1) then R <- R + Z end if
|
||||
* 8: end for
|
||||
* 9: return R
|
||||
* </pre>
|
||||
*/
|
||||
public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
|
||||
ECPoint Q, BigInteger l)
|
||||
{
|
||||
if (!P.getCurve().equals(Q.getCurve()))
|
||||
{
|
||||
throw new IllegalArgumentException("P and Q must be on same curve");
|
||||
}
|
||||
|
||||
return implShamirsTrick(P, k, Q, l);
|
||||
}
|
||||
|
||||
private static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
|
||||
ECPoint Q, BigInteger l)
|
||||
{
|
||||
int m = Math.max(k.bitLength(), l.bitLength());
|
||||
ECPoint Z = P.add(Q);
|
||||
ECPoint R = P.getCurve().getInfinity();
|
||||
|
||||
for (int i = m - 1; i >= 0; --i)
|
||||
{
|
||||
R = R.twice();
|
||||
|
||||
if (k.testBit(i))
|
||||
{
|
||||
if (l.testBit(i))
|
||||
{
|
||||
R = R.add(Z);
|
||||
}
|
||||
else
|
||||
{
|
||||
R = R.add(P);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (l.testBit(i))
|
||||
{
|
||||
R = R.add(Q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public interface ECConstants
|
||||
{
|
||||
public static final BigInteger ZERO = BigInteger.valueOf(0);
|
||||
public static final BigInteger ONE = BigInteger.valueOf(1);
|
||||
public static final BigInteger TWO = BigInteger.valueOf(2);
|
||||
public static final BigInteger THREE = BigInteger.valueOf(3);
|
||||
public static final BigInteger FOUR = BigInteger.valueOf(4);
|
||||
}
|
|
@ -1,660 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* base class for an elliptic curve
|
||||
*/
|
||||
public abstract class ECCurve
|
||||
{
|
||||
ECFieldElement a, b;
|
||||
|
||||
public abstract int getFieldSize();
|
||||
|
||||
public abstract ECFieldElement fromBigInteger(BigInteger x);
|
||||
|
||||
public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);
|
||||
|
||||
public abstract ECPoint decodePoint(byte[] encoded);
|
||||
|
||||
public abstract ECPoint getInfinity();
|
||||
|
||||
public ECFieldElement getA()
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
public ECFieldElement getB()
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Elliptic curve over Fp
|
||||
*/
|
||||
public static class Fp extends ECCurve
|
||||
{
|
||||
BigInteger q;
|
||||
ECPoint.Fp infinity;
|
||||
|
||||
public Fp(BigInteger q, BigInteger a, BigInteger b)
|
||||
{
|
||||
this.q = q;
|
||||
this.a = fromBigInteger(a);
|
||||
this.b = fromBigInteger(b);
|
||||
this.infinity = new ECPoint.Fp(this, null, null);
|
||||
}
|
||||
|
||||
public BigInteger getQ()
|
||||
{
|
||||
return q;
|
||||
}
|
||||
|
||||
public int getFieldSize()
|
||||
{
|
||||
return q.bitLength();
|
||||
}
|
||||
|
||||
public ECFieldElement fromBigInteger(BigInteger x)
|
||||
{
|
||||
return new ECFieldElement.Fp(this.q, x);
|
||||
}
|
||||
|
||||
public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
|
||||
{
|
||||
return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a point on this curve from its ASN.1 encoding. The different
|
||||
* encodings are taken account of, including point compression for
|
||||
* <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
|
||||
* @return The decoded point.
|
||||
*/
|
||||
public ECPoint decodePoint(byte[] encoded)
|
||||
{
|
||||
ECPoint p = null;
|
||||
|
||||
switch (encoded[0])
|
||||
{
|
||||
// infinity
|
||||
case 0x00:
|
||||
p = getInfinity();
|
||||
break;
|
||||
// compressed
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
int ytilde = encoded[0] & 1;
|
||||
byte[] i = new byte[encoded.length - 1];
|
||||
|
||||
System.arraycopy(encoded, 1, i, 0, i.length);
|
||||
|
||||
ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i));
|
||||
ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);
|
||||
ECFieldElement beta = alpha.sqrt();
|
||||
|
||||
//
|
||||
// if we can't find a sqrt we haven't got a point on the
|
||||
// curve - run!
|
||||
//
|
||||
if (beta == null)
|
||||
{
|
||||
throw new RuntimeException("Invalid point compression");
|
||||
}
|
||||
|
||||
int bit0 = (beta.toBigInteger().testBit(0) ? 1 : 0);
|
||||
|
||||
if (bit0 == ytilde)
|
||||
{
|
||||
p = new ECPoint.Fp(this, x, beta, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = new ECPoint.Fp(this, x,
|
||||
new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger())), true);
|
||||
}
|
||||
break;
|
||||
// uncompressed
|
||||
case 0x04:
|
||||
// hybrid
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
byte[] xEnc = new byte[(encoded.length - 1) / 2];
|
||||
byte[] yEnc = new byte[(encoded.length - 1) / 2];
|
||||
|
||||
System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
|
||||
System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
|
||||
|
||||
p = new ECPoint.Fp(this,
|
||||
new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)),
|
||||
new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc)));
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public ECPoint getInfinity()
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
|
||||
public boolean equals(
|
||||
Object anObject)
|
||||
{
|
||||
if (anObject == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(anObject instanceof ECCurve.Fp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ECCurve.Fp other = (ECCurve.Fp) anObject;
|
||||
|
||||
return this.q.equals(other.q)
|
||||
&& a.equals(other.a) && b.equals(other.b);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return a.hashCode() ^ b.hashCode() ^ q.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Elliptic curves over F2m. The Weierstrass equation is given by
|
||||
* <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
|
||||
*/
|
||||
public static class F2m extends ECCurve
|
||||
{
|
||||
/**
|
||||
* The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
*/
|
||||
private int m; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k</sup> + 1</code> represents the reduction polynomial
|
||||
* <code>f(z)</code>.<br>
|
||||
* PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.<br>
|
||||
*/
|
||||
private int k1; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* TPB: Always set to <code>0</code><br>
|
||||
* PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.<br>
|
||||
*/
|
||||
private int k2; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* TPB: Always set to <code>0</code><br>
|
||||
* PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.<br>
|
||||
*/
|
||||
private int k3; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* The order of the base point of the curve.
|
||||
*/
|
||||
private BigInteger n; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* The cofactor of the curve.
|
||||
*/
|
||||
private BigInteger h; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* The point at infinity on this curve.
|
||||
*/
|
||||
private ECPoint.F2m infinity; // can't be final - JDK 1.1
|
||||
|
||||
/**
|
||||
* The parameter <code>μ</code> of the elliptic curve if this is
|
||||
* a Koblitz curve.
|
||||
*/
|
||||
private byte mu = 0;
|
||||
|
||||
/**
|
||||
* The auxiliary values <code>s<sub>0</sub></code> and
|
||||
* <code>s<sub>1</sub></code> used for partial modular reduction for
|
||||
* Koblitz curves.
|
||||
*/
|
||||
private BigInteger[] si = null;
|
||||
|
||||
/**
|
||||
* Constructor for Trinomial Polynomial Basis (TPB).
|
||||
* @param m The exponent <code>m</code> of
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param k The integer <code>k</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k</sup> + 1</code> represents the reduction
|
||||
* polynomial <code>f(z)</code>.
|
||||
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
*/
|
||||
public F2m(
|
||||
int m,
|
||||
int k,
|
||||
BigInteger a,
|
||||
BigInteger b)
|
||||
{
|
||||
this(m, k, 0, 0, a, b, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Trinomial Polynomial Basis (TPB).
|
||||
* @param m The exponent <code>m</code> of
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param k The integer <code>k</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k</sup> + 1</code> represents the reduction
|
||||
* polynomial <code>f(z)</code>.
|
||||
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param n The order of the main subgroup of the elliptic curve.
|
||||
* @param h The cofactor of the elliptic curve, i.e.
|
||||
* <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
|
||||
*/
|
||||
public F2m(
|
||||
int m,
|
||||
int k,
|
||||
BigInteger a,
|
||||
BigInteger b,
|
||||
BigInteger n,
|
||||
BigInteger h)
|
||||
{
|
||||
this(m, k, 0, 0, a, b, n, h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Pentanomial Polynomial Basis (PPB).
|
||||
* @param m The exponent <code>m</code> of
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.
|
||||
* @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.
|
||||
* @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.
|
||||
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
*/
|
||||
public F2m(
|
||||
int m,
|
||||
int k1,
|
||||
int k2,
|
||||
int k3,
|
||||
BigInteger a,
|
||||
BigInteger b)
|
||||
{
|
||||
this(m, k1, k2, k3, a, b, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Pentanomial Polynomial Basis (PPB).
|
||||
* @param m The exponent <code>m</code> of
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.
|
||||
* @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.
|
||||
* @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
|
||||
* x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
|
||||
* represents the reduction polynomial <code>f(z)</code>.
|
||||
* @param a The coefficient <code>a</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param b The coefficient <code>b</code> in the Weierstrass equation
|
||||
* for non-supersingular elliptic curves over
|
||||
* <code>F<sub>2<sup>m</sup></sub></code>.
|
||||
* @param n The order of the main subgroup of the elliptic curve.
|
||||
* @param h The cofactor of the elliptic curve, i.e.
|
||||
* <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
|
||||
*/
|
||||
public F2m(
|
||||
int m,
|
||||
int k1,
|
||||
int k2,
|
||||
int k3,
|
||||
BigInteger a,
|
||||
BigInteger b,
|
||||
BigInteger n,
|
||||
BigInteger h)
|
||||
{
|
||||
this.m = m;
|
||||
this.k1 = k1;
|
||||
this.k2 = k2;
|
||||
this.k3 = k3;
|
||||
this.n = n;
|
||||
this.h = h;
|
||||
|
||||
if (k1 == 0)
|
||||
{
|
||||
throw new IllegalArgumentException("k1 must be > 0");
|
||||
}
|
||||
|
||||
if (k2 == 0)
|
||||
{
|
||||
if (k3 != 0)
|
||||
{
|
||||
throw new IllegalArgumentException("k3 must be 0 if k2 == 0");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (k2 <= k1)
|
||||
{
|
||||
throw new IllegalArgumentException("k2 must be > k1");
|
||||
}
|
||||
|
||||
if (k3 <= k2)
|
||||
{
|
||||
throw new IllegalArgumentException("k3 must be > k2");
|
||||
}
|
||||
}
|
||||
|
||||
this.a = fromBigInteger(a);
|
||||
this.b = fromBigInteger(b);
|
||||
this.infinity = new ECPoint.F2m(this, null, null);
|
||||
}
|
||||
|
||||
public int getFieldSize()
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
public ECFieldElement fromBigInteger(BigInteger x)
|
||||
{
|
||||
return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
|
||||
}
|
||||
|
||||
public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
|
||||
{
|
||||
return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.math.ec.ECCurve#decodePoint(byte[])
|
||||
*/
|
||||
public ECPoint decodePoint(byte[] encoded)
|
||||
{
|
||||
ECPoint p = null;
|
||||
|
||||
switch (encoded[0])
|
||||
{
|
||||
// infinity
|
||||
case 0x00:
|
||||
p = getInfinity();
|
||||
break;
|
||||
// compressed
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
byte[] enc = new byte[encoded.length - 1];
|
||||
System.arraycopy(encoded, 1, enc, 0, enc.length);
|
||||
if (encoded[0] == 0x02)
|
||||
{
|
||||
p = decompressPoint(enc, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = decompressPoint(enc, 1);
|
||||
}
|
||||
break;
|
||||
// uncompressed
|
||||
case 0x04:
|
||||
// hybrid
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
byte[] xEnc = new byte[(encoded.length - 1) / 2];
|
||||
byte[] yEnc = new byte[(encoded.length - 1) / 2];
|
||||
|
||||
System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
|
||||
System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
|
||||
|
||||
p = new ECPoint.F2m(this,
|
||||
new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
|
||||
new BigInteger(1, xEnc)),
|
||||
new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
|
||||
new BigInteger(1, yEnc)), false);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public ECPoint getInfinity()
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a Koblitz curve (ABC curve).
|
||||
* @return true if this is a Koblitz curve (ABC curve), false otherwise
|
||||
*/
|
||||
public boolean isKoblitz()
|
||||
{
|
||||
return ((n != null) && (h != null) &&
|
||||
((a.toBigInteger().equals(ECConstants.ZERO)) ||
|
||||
(a.toBigInteger().equals(ECConstants.ONE))) &&
|
||||
(b.toBigInteger().equals(ECConstants.ONE)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter <code>μ</code> of the elliptic curve.
|
||||
* @return <code>μ</code> of the elliptic curve.
|
||||
* @throws IllegalArgumentException if the given ECCurve is not a
|
||||
* Koblitz curve.
|
||||
*/
|
||||
synchronized byte getMu()
|
||||
{
|
||||
if (mu == 0)
|
||||
{
|
||||
mu = Tnaf.getMu(this);
|
||||
}
|
||||
return mu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the auxiliary values <code>s<sub>0</sub></code> and
|
||||
* <code>s<sub>1</sub></code> used for partial modular reduction for
|
||||
* Koblitz curves.
|
||||
*/
|
||||
synchronized BigInteger[] getSi()
|
||||
{
|
||||
if (si == null)
|
||||
{
|
||||
si = Tnaf.getSi(this);
|
||||
}
|
||||
return si;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
|
||||
*
|
||||
* @param xEnc
|
||||
* The encoding of field element xp.
|
||||
* @param ypBit
|
||||
* ~yp, an indication bit for the decompression of yp.
|
||||
* @return the decompressed point.
|
||||
*/
|
||||
private ECPoint decompressPoint(
|
||||
byte[] xEnc,
|
||||
int ypBit)
|
||||
{
|
||||
ECFieldElement xp = new ECFieldElement.F2m(
|
||||
this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc));
|
||||
ECFieldElement yp = null;
|
||||
if (xp.toBigInteger().equals(ECConstants.ZERO))
|
||||
{
|
||||
yp = (ECFieldElement.F2m)b;
|
||||
for (int i = 0; i < m - 1; i++)
|
||||
{
|
||||
yp = yp.square();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ECFieldElement beta = xp.add(a).add(
|
||||
b.multiply(xp.square().invert()));
|
||||
ECFieldElement z = solveQuadradicEquation(beta);
|
||||
if (z == null)
|
||||
{
|
||||
throw new RuntimeException("Invalid point compression");
|
||||
}
|
||||
int zBit = 0;
|
||||
if (z.toBigInteger().testBit(0))
|
||||
{
|
||||
zBit = 1;
|
||||
}
|
||||
if (zBit != ypBit)
|
||||
{
|
||||
z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2,
|
||||
this.k3, ECConstants.ONE));
|
||||
}
|
||||
yp = xp.multiply(z);
|
||||
}
|
||||
|
||||
return new ECPoint.F2m(this, xp, yp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
|
||||
* D.1.6) The other solution is <code>z + 1</code>.
|
||||
*
|
||||
* @param beta
|
||||
* The value to solve the qradratic equation for.
|
||||
* @return the solution for <code>z<sup>2</sup> + z = beta</code> or
|
||||
* <code>null</code> if no solution exists.
|
||||
*/
|
||||
private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
|
||||
{
|
||||
ECFieldElement zeroElement = new ECFieldElement.F2m(
|
||||
this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);
|
||||
|
||||
if (beta.toBigInteger().equals(ECConstants.ZERO))
|
||||
{
|
||||
return zeroElement;
|
||||
}
|
||||
|
||||
ECFieldElement z = null;
|
||||
ECFieldElement gamma = zeroElement;
|
||||
|
||||
Random rand = new Random();
|
||||
do
|
||||
{
|
||||
ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,
|
||||
this.k2, this.k3, new BigInteger(m, rand));
|
||||
z = zeroElement;
|
||||
ECFieldElement w = beta;
|
||||
for (int i = 1; i <= m - 1; i++)
|
||||
{
|
||||
ECFieldElement w2 = w.square();
|
||||
z = z.square().add(w2.multiply(t));
|
||||
w = w2.add(beta);
|
||||
}
|
||||
if (!w.toBigInteger().equals(ECConstants.ZERO))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
gamma = z.square().add(z);
|
||||
}
|
||||
while (gamma.toBigInteger().equals(ECConstants.ZERO));
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
public boolean equals(
|
||||
Object anObject)
|
||||
{
|
||||
if (anObject == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(anObject instanceof ECCurve.F2m))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ECCurve.F2m other = (ECCurve.F2m)anObject;
|
||||
|
||||
return (this.m == other.m) && (this.k1 == other.k1)
|
||||
&& (this.k2 == other.k2) && (this.k3 == other.k3)
|
||||
&& a.equals(other.a) && b.equals(other.b);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
|
||||
}
|
||||
|
||||
public int getM()
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if curve uses a Trinomial basis.
|
||||
*
|
||||
* @return true if curve Trinomial, false otherwise.
|
||||
*/
|
||||
public boolean isTrinomial()
|
||||
{
|
||||
return k2 == 0 && k3 == 0;
|
||||
}
|
||||
|
||||
public int getK1()
|
||||
{
|
||||
return k1;
|
||||
}
|
||||
|
||||
public int getK2()
|
||||
{
|
||||
return k2;
|
||||
}
|
||||
|
||||
public int getK3()
|
||||
{
|
||||
return k3;
|
||||
}
|
||||
|
||||
public BigInteger getN()
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
public BigInteger getH()
|
||||
{
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,19 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Interface for classes encapsulating a point multiplication algorithm
|
||||
* for <code>ECPoint</code>s.
|
||||
*/
|
||||
interface ECMultiplier
|
||||
{
|
||||
/**
|
||||
* Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.
|
||||
* <code>p</code> is added <code>k</code> times to itself.
|
||||
* @param p The <code>ECPoint</code> to be multiplied.
|
||||
* @param k The factor by which <code>p</code> i multiplied.
|
||||
* @return <code>p</code> multiplied by <code>k</code>.
|
||||
*/
|
||||
ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);
|
||||
}
|
|
@ -1,594 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.thoughtcrime.bouncycastle.asn1.x9.X9IntegerConverter;
|
||||
|
||||
/**
|
||||
* base class for points on elliptic curves.
|
||||
*/
|
||||
public abstract class ECPoint
|
||||
{
|
||||
ECCurve curve;
|
||||
ECFieldElement x;
|
||||
ECFieldElement y;
|
||||
|
||||
protected boolean withCompression;
|
||||
|
||||
protected ECMultiplier multiplier = null;
|
||||
|
||||
protected PreCompInfo preCompInfo = null;
|
||||
|
||||
private static X9IntegerConverter converter = new X9IntegerConverter();
|
||||
|
||||
protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
|
||||
{
|
||||
this.curve = curve;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public ECCurve getCurve()
|
||||
{
|
||||
return curve;
|
||||
}
|
||||
|
||||
public ECFieldElement getX()
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
public ECFieldElement getY()
|
||||
{
|
||||
return y;
|
||||
}
|
||||
|
||||
public boolean isInfinity()
|
||||
{
|
||||
return x == null && y == null;
|
||||
}
|
||||
|
||||
public boolean isCompressed()
|
||||
{
|
||||
return withCompression;
|
||||
}
|
||||
|
||||
public boolean equals(
|
||||
Object other)
|
||||
{
|
||||
if (other == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof ECPoint))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ECPoint o = (ECPoint)other;
|
||||
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return o.isInfinity();
|
||||
}
|
||||
|
||||
return x.equals(o.x) && y.equals(o.y);
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return x.hashCode() ^ y.hashCode();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
|
||||
// * @param multiplier The <code>ECMultiplier</code> to be used to multiply
|
||||
// * this <code>ECPoint</code>.
|
||||
// */
|
||||
// public void setECMultiplier(ECMultiplier multiplier)
|
||||
// {
|
||||
// this.multiplier = multiplier;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
|
||||
* to save the precomputation for this <code>ECPoint</code> to store the
|
||||
* precomputation result for use by subsequent multiplication.
|
||||
* @param preCompInfo The values precomputed by the
|
||||
* <code>ECMultiplier</code>.
|
||||
*/
|
||||
void setPreCompInfo(PreCompInfo preCompInfo)
|
||||
{
|
||||
this.preCompInfo = preCompInfo;
|
||||
}
|
||||
|
||||
public abstract byte[] getEncoded();
|
||||
|
||||
public abstract ECPoint add(ECPoint b);
|
||||
public abstract ECPoint subtract(ECPoint b);
|
||||
public abstract ECPoint negate();
|
||||
public abstract ECPoint twice();
|
||||
|
||||
/**
|
||||
* Sets the default <code>ECMultiplier</code>, unless already set.
|
||||
*/
|
||||
synchronized void assertECMultiplier()
|
||||
{
|
||||
if (this.multiplier == null)
|
||||
{
|
||||
this.multiplier = new FpNafMultiplier();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this <code>ECPoint</code> by the given number.
|
||||
* @param k The multiplicator.
|
||||
* @return <code>k * this</code>.
|
||||
*/
|
||||
public ECPoint multiply(BigInteger k)
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (k.signum() == 0)
|
||||
{
|
||||
return this.curve.getInfinity();
|
||||
}
|
||||
|
||||
assertECMultiplier();
|
||||
return this.multiplier.multiply(this, k, preCompInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Elliptic curve points over Fp
|
||||
*/
|
||||
public static class Fp extends ECPoint
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a point which encodes with point compression.
|
||||
*
|
||||
* @param curve the curve to use
|
||||
* @param x affine x co-ordinate
|
||||
* @param y affine y co-ordinate
|
||||
*/
|
||||
public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y)
|
||||
{
|
||||
this(curve, x, y, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a point that encodes with or without point compresion.
|
||||
*
|
||||
* @param curve the curve to use
|
||||
* @param x affine x co-ordinate
|
||||
* @param y affine y co-ordinate
|
||||
* @param withCompression if true encode with point compression
|
||||
*/
|
||||
public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
|
||||
{
|
||||
super(curve, x, y);
|
||||
|
||||
if ((x != null && y == null) || (x == null && y != null))
|
||||
{
|
||||
throw new IllegalArgumentException("Exactly one of the field elements is null");
|
||||
}
|
||||
|
||||
this.withCompression = withCompression;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the field element encoded with point compression. (S 4.3.6)
|
||||
*/
|
||||
public byte[] getEncoded()
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return new byte[1];
|
||||
}
|
||||
|
||||
int qLength = converter.getByteLength(x);
|
||||
|
||||
if (withCompression)
|
||||
{
|
||||
byte PC;
|
||||
|
||||
if (this.getY().toBigInteger().testBit(0))
|
||||
{
|
||||
PC = 0x03;
|
||||
}
|
||||
else
|
||||
{
|
||||
PC = 0x02;
|
||||
}
|
||||
|
||||
byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
|
||||
byte[] PO = new byte[X.length + 1];
|
||||
|
||||
PO[0] = PC;
|
||||
System.arraycopy(X, 0, PO, 1, X.length);
|
||||
|
||||
return PO;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
|
||||
byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
|
||||
byte[] PO = new byte[X.length + Y.length + 1];
|
||||
|
||||
PO[0] = 0x04;
|
||||
System.arraycopy(X, 0, PO, 1, X.length);
|
||||
System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
|
||||
|
||||
return PO;
|
||||
}
|
||||
}
|
||||
|
||||
// B.3 pg 62
|
||||
public ECPoint add(ECPoint b)
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return b;
|
||||
}
|
||||
|
||||
if (b.isInfinity())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// Check if b = this or b = -this
|
||||
if (this.x.equals(b.x))
|
||||
{
|
||||
if (this.y.equals(b.y))
|
||||
{
|
||||
// this = b, i.e. this must be doubled
|
||||
return this.twice();
|
||||
}
|
||||
|
||||
// this = -b, i.e. the result is the point at infinity
|
||||
return this.curve.getInfinity();
|
||||
}
|
||||
|
||||
ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
|
||||
|
||||
ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
|
||||
ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
||||
|
||||
return new ECPoint.Fp(curve, x3, y3);
|
||||
}
|
||||
|
||||
// B.3 pg 62
|
||||
public ECPoint twice()
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
// Twice identity element (point at infinity) is identity
|
||||
return this;
|
||||
}
|
||||
|
||||
if (this.y.toBigInteger().signum() == 0)
|
||||
{
|
||||
// if y1 == 0, then (x1, y1) == (x1, -y1)
|
||||
// and hence this = -this and thus 2(x1, y1) == infinity
|
||||
return this.curve.getInfinity();
|
||||
}
|
||||
|
||||
ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
|
||||
ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
|
||||
ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
|
||||
|
||||
ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
|
||||
ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
|
||||
|
||||
return new ECPoint.Fp(curve, x3, y3, this.withCompression);
|
||||
}
|
||||
|
||||
// D.3.2 pg 102 (see Note:)
|
||||
public ECPoint subtract(ECPoint b)
|
||||
{
|
||||
if (b.isInfinity())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// Add -b
|
||||
return add(b.negate());
|
||||
}
|
||||
|
||||
public ECPoint negate()
|
||||
{
|
||||
return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
|
||||
}
|
||||
|
||||
// TODO Uncomment this to enable WNAF algorithm for Fp point multiplication
|
||||
// /**
|
||||
// * Sets the default <code>ECMultiplier</code>, unless already set.
|
||||
// */
|
||||
// synchronized void assertECMultiplier()
|
||||
// {
|
||||
// if (this.multiplier == null)
|
||||
// {
|
||||
// this.multiplier = new WNafMultiplier();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Elliptic curve points over F2m
|
||||
*/
|
||||
public static class F2m extends ECPoint
|
||||
{
|
||||
/**
|
||||
* @param curve base curve
|
||||
* @param x x point
|
||||
* @param y y point
|
||||
*/
|
||||
public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
|
||||
{
|
||||
this(curve, x, y, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param curve base curve
|
||||
* @param x x point
|
||||
* @param y y point
|
||||
* @param withCompression true if encode with point compression.
|
||||
*/
|
||||
public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
|
||||
{
|
||||
super(curve, x, y);
|
||||
|
||||
if ((x != null && y == null) || (x == null && y != null))
|
||||
{
|
||||
throw new IllegalArgumentException("Exactly one of the field elements is null");
|
||||
}
|
||||
|
||||
if (x != null)
|
||||
{
|
||||
// Check if x and y are elements of the same field
|
||||
ECFieldElement.F2m.checkFieldElements(this.x, this.y);
|
||||
|
||||
// Check if x and a are elements of the same field
|
||||
if (curve != null)
|
||||
{
|
||||
ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
|
||||
}
|
||||
}
|
||||
|
||||
this.withCompression = withCompression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use ECCurve.getInfinity()
|
||||
* Constructor for point at infinity
|
||||
*/
|
||||
public F2m(ECCurve curve)
|
||||
{
|
||||
super(curve, null, null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.math.ec.ECPoint#getEncoded()
|
||||
*/
|
||||
public byte[] getEncoded()
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return new byte[1];
|
||||
}
|
||||
|
||||
int byteCount = converter.getByteLength(this.x);
|
||||
byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
|
||||
byte[] PO;
|
||||
|
||||
if (withCompression)
|
||||
{
|
||||
// See X9.62 4.3.6 and 4.2.2
|
||||
PO = new byte[byteCount + 1];
|
||||
|
||||
PO[0] = 0x02;
|
||||
// X9.62 4.2.2 and 4.3.6:
|
||||
// if x = 0 then ypTilde := 0, else ypTilde is the rightmost
|
||||
// bit of y * x^(-1)
|
||||
// if ypTilde = 0, then PC := 02, else PC := 03
|
||||
// Note: PC === PO[0]
|
||||
if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
|
||||
{
|
||||
if (this.getY().multiply(this.getX().invert())
|
||||
.toBigInteger().testBit(0))
|
||||
{
|
||||
// ypTilde = 1, hence PC = 03
|
||||
PO[0] = 0x03;
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(X, 0, PO, 1, byteCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
|
||||
|
||||
PO = new byte[byteCount + byteCount + 1];
|
||||
|
||||
PO[0] = 0x04;
|
||||
System.arraycopy(X, 0, PO, 1, byteCount);
|
||||
System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
|
||||
}
|
||||
|
||||
return PO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check, if two <code>ECPoint</code>s can be added or subtracted.
|
||||
* @param a The first <code>ECPoint</code> to check.
|
||||
* @param b The second <code>ECPoint</code> to check.
|
||||
* @throws IllegalArgumentException if <code>a</code> and <code>b</code>
|
||||
* cannot be added.
|
||||
*/
|
||||
private static void checkPoints(ECPoint a, ECPoint b)
|
||||
{
|
||||
// Check, if points are on the same curve
|
||||
if (!(a.curve.equals(b.curve)))
|
||||
{
|
||||
throw new IllegalArgumentException("Only points on the same "
|
||||
+ "curve can be added or subtracted");
|
||||
}
|
||||
|
||||
// ECFieldElement.F2m.checkFieldElements(a.x, b.x);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint)
|
||||
*/
|
||||
public ECPoint add(ECPoint b)
|
||||
{
|
||||
checkPoints(this, b);
|
||||
return addSimple((ECPoint.F2m)b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another <code>ECPoints.F2m</code> to <code>this</code> without
|
||||
* checking if both points are on the same curve. Used by multiplication
|
||||
* algorithms, because there all points are a multiple of the same point
|
||||
* and hence the checks can be omitted.
|
||||
* @param b The other <code>ECPoints.F2m</code> to add to
|
||||
* <code>this</code>.
|
||||
* @return <code>this + b</code>
|
||||
*/
|
||||
public ECPoint.F2m addSimple(ECPoint.F2m b)
|
||||
{
|
||||
ECPoint.F2m other = b;
|
||||
if (this.isInfinity())
|
||||
{
|
||||
return other;
|
||||
}
|
||||
|
||||
if (other.isInfinity())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
|
||||
ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
|
||||
|
||||
// Check if other = this or other = -this
|
||||
if (this.x.equals(x2))
|
||||
{
|
||||
if (this.y.equals(y2))
|
||||
{
|
||||
// this = other, i.e. this must be doubled
|
||||
return (ECPoint.F2m)this.twice();
|
||||
}
|
||||
|
||||
// this = -other, i.e. the result is the point at infinity
|
||||
return (ECPoint.F2m)this.curve.getInfinity();
|
||||
}
|
||||
|
||||
ECFieldElement.F2m lambda
|
||||
= (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
|
||||
|
||||
ECFieldElement.F2m x3
|
||||
= (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
|
||||
|
||||
ECFieldElement.F2m y3
|
||||
= (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
|
||||
|
||||
return new ECPoint.F2m(curve, x3, y3, withCompression);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint)
|
||||
*/
|
||||
public ECPoint subtract(ECPoint b)
|
||||
{
|
||||
checkPoints(this, b);
|
||||
return subtractSimple((ECPoint.F2m)b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts another <code>ECPoints.F2m</code> from <code>this</code>
|
||||
* without checking if both points are on the same curve. Used by
|
||||
* multiplication algorithms, because there all points are a multiple
|
||||
* of the same point and hence the checks can be omitted.
|
||||
* @param b The other <code>ECPoints.F2m</code> to subtract from
|
||||
* <code>this</code>.
|
||||
* @return <code>this - b</code>
|
||||
*/
|
||||
public ECPoint.F2m subtractSimple(ECPoint.F2m b)
|
||||
{
|
||||
if (b.isInfinity())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
// Add -b
|
||||
return addSimple((ECPoint.F2m)b.negate());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.bouncycastle.math.ec.ECPoint#twice()
|
||||
*/
|
||||
public ECPoint twice()
|
||||
{
|
||||
if (this.isInfinity())
|
||||
{
|
||||
// Twice identity element (point at infinity) is identity
|
||||
return this;
|
||||
}
|
||||
|
||||
if (this.x.toBigInteger().signum() == 0)
|
||||
{
|
||||
// if x1 == 0, then (x1, y1) == (x1, x1 + y1)
|
||||
// and hence this = -this and thus 2(x1, y1) == infinity
|
||||
return this.curve.getInfinity();
|
||||
}
|
||||
|
||||
ECFieldElement.F2m lambda
|
||||
= (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
|
||||
|
||||
ECFieldElement.F2m x3
|
||||
= (ECFieldElement.F2m)lambda.square().add(lambda).
|
||||
add(this.curve.getA());
|
||||
|
||||
ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
|
||||
ECFieldElement.F2m y3
|
||||
= (ECFieldElement.F2m)this.x.square().add(
|
||||
x3.multiply(lambda.add(ONE)));
|
||||
|
||||
return new ECPoint.F2m(this.curve, x3, y3, withCompression);
|
||||
}
|
||||
|
||||
public ECPoint negate()
|
||||
{
|
||||
return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
|
||||
}
|
||||
|
||||
// TODO Uncomment this to enable WNAF/WTNAF F2m point multiplication
|
||||
// /**
|
||||
// * Sets the appropriate <code>ECMultiplier</code>, unless already set.
|
||||
// */
|
||||
// synchronized void assertECMultiplier()
|
||||
// {
|
||||
// if (this.multiplier == null)
|
||||
// {
|
||||
// if (((ECCurve.F2m)(this.curve)).isKoblitz())
|
||||
// {
|
||||
// this.multiplier = new WTauNafMultiplier();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.multiplier = new WNafMultiplier();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
|
||||
*/
|
||||
class FpNafMultiplier implements ECMultiplier
|
||||
{
|
||||
/**
|
||||
* D.3.2 pg 101
|
||||
* @see org.bouncycastle.math.ec.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
|
||||
*/
|
||||
public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
|
||||
{
|
||||
// TODO Probably should try to add this
|
||||
// BigInteger e = k.mod(n); // n == order of p
|
||||
BigInteger e = k;
|
||||
BigInteger h = e.multiply(BigInteger.valueOf(3));
|
||||
|
||||
ECPoint neg = p.negate();
|
||||
ECPoint R = p;
|
||||
|
||||
for (int i = h.bitLength() - 2; i > 0; --i)
|
||||
{
|
||||
R = R.twice();
|
||||
|
||||
boolean hBit = h.testBit(i);
|
||||
boolean eBit = e.testBit(i);
|
||||
|
||||
if (hBit != eBit)
|
||||
{
|
||||
R = R.add(hBit ? p : neg);
|
||||
}
|
||||
}
|
||||
|
||||
return R;
|
||||
}
|
||||
}
|
|
@ -1,518 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
class IntArray
|
||||
{
|
||||
// TODO make m fixed for the IntArray, and hence compute T once and for all
|
||||
|
||||
private int[] m_ints;
|
||||
|
||||
public IntArray(int intLen)
|
||||
{
|
||||
m_ints = new int[intLen];
|
||||
}
|
||||
|
||||
public IntArray(int[] ints)
|
||||
{
|
||||
m_ints = ints;
|
||||
}
|
||||
|
||||
public IntArray(BigInteger bigInt)
|
||||
{
|
||||
this(bigInt, 0);
|
||||
}
|
||||
|
||||
public IntArray(BigInteger bigInt, int minIntLen)
|
||||
{
|
||||
if (bigInt.signum() == -1)
|
||||
{
|
||||
throw new IllegalArgumentException("Only positive Integers allowed");
|
||||
}
|
||||
if (bigInt.equals(ECConstants.ZERO))
|
||||
{
|
||||
m_ints = new int[] { 0 };
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] barr = bigInt.toByteArray();
|
||||
int barrLen = barr.length;
|
||||
int barrStart = 0;
|
||||
if (barr[0] == 0)
|
||||
{
|
||||
// First byte is 0 to enforce highest (=sign) bit is zero.
|
||||
// In this case ignore barr[0].
|
||||
barrLen--;
|
||||
barrStart = 1;
|
||||
}
|
||||
int intLen = (barrLen + 3) / 4;
|
||||
if (intLen < minIntLen)
|
||||
{
|
||||
m_ints = new int[minIntLen];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ints = new int[intLen];
|
||||
}
|
||||
|
||||
int iarrJ = intLen - 1;
|
||||
int rem = barrLen % 4 + barrStart;
|
||||
int temp = 0;
|
||||
int barrI = barrStart;
|
||||
if (barrStart < rem)
|
||||
{
|
||||
for (; barrI < rem; barrI++)
|
||||
{
|
||||
temp <<= 8;
|
||||
int barrBarrI = barr[barrI];
|
||||
if (barrBarrI < 0)
|
||||
{
|
||||
barrBarrI += 256;
|
||||
}
|
||||
temp |= barrBarrI;
|
||||
}
|
||||
m_ints[iarrJ--] = temp;
|
||||
}
|
||||
|
||||
for (; iarrJ >= 0; iarrJ--)
|
||||
{
|
||||
temp = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
temp <<= 8;
|
||||
int barrBarrI = barr[barrI++];
|
||||
if (barrBarrI < 0)
|
||||
{
|
||||
barrBarrI += 256;
|
||||
}
|
||||
temp |= barrBarrI;
|
||||
}
|
||||
m_ints[iarrJ] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isZero()
|
||||
{
|
||||
return m_ints.length == 0
|
||||
|| (m_ints[0] == 0 && getUsedLength() == 0);
|
||||
}
|
||||
|
||||
public int getUsedLength()
|
||||
{
|
||||
int highestIntPos = m_ints.length;
|
||||
|
||||
if (highestIntPos < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if first element will act as sentinel
|
||||
if (m_ints[0] != 0)
|
||||
{
|
||||
while (m_ints[--highestIntPos] == 0)
|
||||
{
|
||||
}
|
||||
return highestIntPos + 1;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (m_ints[--highestIntPos] != 0)
|
||||
{
|
||||
return highestIntPos + 1;
|
||||
}
|
||||
}
|
||||
while (highestIntPos > 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int bitLength()
|
||||
{
|
||||
// JDK 1.5: see Integer.numberOfLeadingZeros()
|
||||
int intLen = getUsedLength();
|
||||
if (intLen == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int last = intLen - 1;
|
||||
int highest = m_ints[last];
|
||||
int bits = (last << 5) + 1;
|
||||
|
||||
// A couple of binary search steps
|
||||
if ((highest & 0xffff0000) != 0)
|
||||
{
|
||||
if ((highest & 0xff000000) != 0)
|
||||
{
|
||||
bits += 24;
|
||||
highest >>>= 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
bits += 16;
|
||||
highest >>>= 16;
|
||||
}
|
||||
}
|
||||
else if (highest > 0x000000ff)
|
||||
{
|
||||
bits += 8;
|
||||
highest >>>= 8;
|
||||
}
|
||||
|
||||
while (highest != 1)
|
||||
{
|
||||
++bits;
|
||||
highest >>>= 1;
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
private int[] resizedInts(int newLen)
|
||||
{
|
||||
int[] newInts = new int[newLen];
|
||||
int oldLen = m_ints.length;
|
||||
int copyLen = oldLen < newLen ? oldLen : newLen;
|
||||
System.arraycopy(m_ints, 0, newInts, 0, copyLen);
|
||||
return newInts;
|
||||
}
|
||||
|
||||
public BigInteger toBigInteger()
|
||||
{
|
||||
int usedLen = getUsedLength();
|
||||
if (usedLen == 0)
|
||||
{
|
||||
return ECConstants.ZERO;
|
||||
}
|
||||
|
||||
int highestInt = m_ints[usedLen - 1];
|
||||
byte[] temp = new byte[4];
|
||||
int barrI = 0;
|
||||
boolean trailingZeroBytesDone = false;
|
||||
for (int j = 3; j >= 0; j--)
|
||||
{
|
||||
byte thisByte = (byte) (highestInt >>> (8 * j));
|
||||
if (trailingZeroBytesDone || (thisByte != 0))
|
||||
{
|
||||
trailingZeroBytesDone = true;
|
||||
temp[barrI++] = thisByte;
|
||||
}
|
||||
}
|
||||
|
||||
int barrLen = 4 * (usedLen - 1) + barrI;
|
||||
byte[] barr = new byte[barrLen];
|
||||
for (int j = 0; j < barrI; j++)
|
||||
{
|
||||
barr[j] = temp[j];
|
||||
}
|
||||
// Highest value int is done now
|
||||
|
||||
for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
|
||||
{
|
||||
for (int j = 3; j >= 0; j--)
|
||||
{
|
||||
barr[barrI++] = (byte) (m_ints[iarrJ] >>> (8 * j));
|
||||
}
|
||||
}
|
||||
return new BigInteger(1, barr);
|
||||
}
|
||||
|
||||
public void shiftLeft()
|
||||
{
|
||||
int usedLen = getUsedLength();
|
||||
if (usedLen == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (m_ints[usedLen - 1] < 0)
|
||||
{
|
||||
// highest bit of highest used byte is set, so shifting left will
|
||||
// make the IntArray one byte longer
|
||||
usedLen++;
|
||||
if (usedLen > m_ints.length)
|
||||
{
|
||||
// make the m_ints one byte longer, because we need one more
|
||||
// byte which is not available in m_ints
|
||||
m_ints = resizedInts(m_ints.length + 1);
|
||||
}
|
||||
}
|
||||
|
||||
boolean carry = false;
|
||||
for (int i = 0; i < usedLen; i++)
|
||||
{
|
||||
// nextCarry is true if highest bit is set
|
||||
boolean nextCarry = m_ints[i] < 0;
|
||||
m_ints[i] <<= 1;
|
||||
if (carry)
|
||||
{
|
||||
// set lowest bit
|
||||
m_ints[i] |= 1;
|
||||
}
|
||||
carry = nextCarry;
|
||||
}
|
||||
}
|
||||
|
||||
public IntArray shiftLeft(int n)
|
||||
{
|
||||
int usedLen = getUsedLength();
|
||||
if (usedLen == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (n > 31)
|
||||
{
|
||||
throw new IllegalArgumentException("shiftLeft() for max 31 bits "
|
||||
+ ", " + n + "bit shift is not possible");
|
||||
}
|
||||
|
||||
int[] newInts = new int[usedLen + 1];
|
||||
|
||||
int nm32 = 32 - n;
|
||||
newInts[0] = m_ints[0] << n;
|
||||
for (int i = 1; i < usedLen; i++)
|
||||
{
|
||||
newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);
|
||||
}
|
||||
newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;
|
||||
|
||||
return new IntArray(newInts);
|
||||
}
|
||||
|
||||
public void addShifted(IntArray other, int shift)
|
||||
{
|
||||
int usedLenOther = other.getUsedLength();
|
||||
int newMinUsedLen = usedLenOther + shift;
|
||||
if (newMinUsedLen > m_ints.length)
|
||||
{
|
||||
m_ints = resizedInts(newMinUsedLen);
|
||||
//System.out.println("Resize required");
|
||||
}
|
||||
|
||||
for (int i = 0; i < usedLenOther; i++)
|
||||
{
|
||||
m_ints[i + shift] ^= other.m_ints[i];
|
||||
}
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
return m_ints.length;
|
||||
}
|
||||
|
||||
public boolean testBit(int n)
|
||||
{
|
||||
// theInt = n / 32
|
||||
int theInt = n >> 5;
|
||||
// theBit = n % 32
|
||||
int theBit = n & 0x1F;
|
||||
int tester = 1 << theBit;
|
||||
return ((m_ints[theInt] & tester) != 0);
|
||||
}
|
||||
|
||||
public void flipBit(int n)
|
||||
{
|
||||
// theInt = n / 32
|
||||
int theInt = n >> 5;
|
||||
// theBit = n % 32
|
||||
int theBit = n & 0x1F;
|
||||
int flipper = 1 << theBit;
|
||||
m_ints[theInt] ^= flipper;
|
||||
}
|
||||
|
||||
public void setBit(int n)
|
||||
{
|
||||
// theInt = n / 32
|
||||
int theInt = n >> 5;
|
||||
// theBit = n % 32
|
||||
int theBit = n & 0x1F;
|
||||
int setter = 1 << theBit;
|
||||
m_ints[theInt] |= setter;
|
||||
}
|
||||
|
||||
public IntArray multiply(IntArray other, int m)
|
||||
{
|
||||
// Lenght of c is 2m bits rounded up to the next int (32 bit)
|
||||
int t = (m + 31) >> 5;
|
||||
if (m_ints.length < t)
|
||||
{
|
||||
m_ints = resizedInts(t);
|
||||
}
|
||||
|
||||
IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
|
||||
IntArray c = new IntArray((m + m + 31) >> 5);
|
||||
// IntArray c = new IntArray(t + t);
|
||||
int testBit = 1;
|
||||
for (int k = 0; k < 32; k++)
|
||||
{
|
||||
for (int j = 0; j < t; j++)
|
||||
{
|
||||
if ((m_ints[j] & testBit) != 0)
|
||||
{
|
||||
// The kth bit of m_ints[j] is set
|
||||
c.addShifted(b, j);
|
||||
}
|
||||
}
|
||||
testBit <<= 1;
|
||||
b.shiftLeft();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// public IntArray multiplyLeftToRight(IntArray other, int m) {
|
||||
// // Lenght of c is 2m bits rounded up to the next int (32 bit)
|
||||
// int t = (m + 31) / 32;
|
||||
// if (m_ints.length < t) {
|
||||
// m_ints = resizedInts(t);
|
||||
// }
|
||||
//
|
||||
// IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
|
||||
// IntArray c = new IntArray((m + m + 31) / 32);
|
||||
// // IntArray c = new IntArray(t + t);
|
||||
// int testBit = 1 << 31;
|
||||
// for (int k = 31; k >= 0; k--) {
|
||||
// for (int j = 0; j < t; j++) {
|
||||
// if ((m_ints[j] & testBit) != 0) {
|
||||
// // The kth bit of m_ints[j] is set
|
||||
// c.addShifted(b, j);
|
||||
// }
|
||||
// }
|
||||
// testBit >>>= 1;
|
||||
// if (k > 0) {
|
||||
// c.shiftLeft();
|
||||
// }
|
||||
// }
|
||||
// return c;
|
||||
// }
|
||||
|
||||
// TODO note, redPol.length must be 3 for TPB and 5 for PPB
|
||||
public void reduce(int m, int[] redPol)
|
||||
{
|
||||
for (int i = m + m - 2; i >= m; i--)
|
||||
{
|
||||
if (testBit(i))
|
||||
{
|
||||
int bit = i - m;
|
||||
flipBit(bit);
|
||||
flipBit(i);
|
||||
int l = redPol.length;
|
||||
while (--l >= 0)
|
||||
{
|
||||
flipBit(redPol[l] + bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_ints = resizedInts((m + 31) >> 5);
|
||||
}
|
||||
|
||||
public IntArray square(int m)
|
||||
{
|
||||
// TODO make the table static final
|
||||
final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
|
||||
0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
|
||||
|
||||
int t = (m + 31) >> 5;
|
||||
if (m_ints.length < t)
|
||||
{
|
||||
m_ints = resizedInts(t);
|
||||
}
|
||||
|
||||
IntArray c = new IntArray(t + t);
|
||||
|
||||
// TODO twice the same code, put in separate private method
|
||||
for (int i = 0; i < t; i++)
|
||||
{
|
||||
int v0 = 0;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
v0 = v0 >>> 8;
|
||||
int u = (m_ints[i] >>> (j * 4)) & 0xF;
|
||||
int w = table[u] << 24;
|
||||
v0 |= w;
|
||||
}
|
||||
c.m_ints[i + i] = v0;
|
||||
|
||||
v0 = 0;
|
||||
int upper = m_ints[i] >>> 16;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
v0 = v0 >>> 8;
|
||||
int u = (upper >>> (j * 4)) & 0xF;
|
||||
int w = table[u] << 24;
|
||||
v0 |= w;
|
||||
}
|
||||
c.m_ints[i + i + 1] = v0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (!(o instanceof IntArray))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
IntArray other = (IntArray) o;
|
||||
int usedLen = getUsedLength();
|
||||
if (other.getUsedLength() != usedLen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < usedLen; i++)
|
||||
{
|
||||
if (m_ints[i] != other.m_ints[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
int usedLen = getUsedLength();
|
||||
int hash = 1;
|
||||
for (int i = 0; i < usedLen; i++)
|
||||
{
|
||||
hash = hash * 31 + m_ints[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
public Object clone()
|
||||
{
|
||||
return new IntArray(Arrays.clone(m_ints));
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
int usedLen = getUsedLength();
|
||||
if (usedLen == 0)
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer(Integer
|
||||
.toBinaryString(m_ints[usedLen - 1]));
|
||||
for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
|
||||
{
|
||||
String hexString = Integer.toBinaryString(m_ints[iarrJ]);
|
||||
|
||||
// Add leading zeroes, except for highest significant int
|
||||
for (int i = hexString.length(); i < 8; i++)
|
||||
{
|
||||
hexString = "0" + hexString;
|
||||
}
|
||||
sb.append(hexString);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
/**
|
||||
* Interface for classes storing precomputation data for multiplication
|
||||
* algorithms. Used as a Memento (see GOF patterns) for
|
||||
* <code>WNafMultiplier</code>.
|
||||
*/
|
||||
interface PreCompInfo
|
||||
{
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
class ReferenceMultiplier implements ECMultiplier
|
||||
{
|
||||
/**
|
||||
* Simple shift-and-add multiplication. Serves as reference implementation
|
||||
* to verify (possibly faster) implementations in
|
||||
* {@link org.bouncycastle.math.ec.ECPoint ECPoint}.
|
||||
*
|
||||
* @param p The point to multiply.
|
||||
* @param k The factor by which to multiply.
|
||||
* @return The result of the point multiplication <code>k * p</code>.
|
||||
*/
|
||||
public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
|
||||
{
|
||||
ECPoint q = p.getCurve().getInfinity();
|
||||
int t = k.bitLength();
|
||||
for (int i = 0; i < t; i++)
|
||||
{
|
||||
if (k.testBit(i))
|
||||
{
|
||||
q = q.add(p);
|
||||
}
|
||||
p = p.twice();
|
||||
}
|
||||
return q;
|
||||
}
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Class representing a simple version of a big decimal. A
|
||||
* <code>SimpleBigDecimal</code> is basically a
|
||||
* {@link java.math.BigInteger BigInteger} with a few digits on the right of
|
||||
* the decimal point. The number of (binary) digits on the right of the decimal
|
||||
* point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.
|
||||
* Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
|
||||
* automatically, but must be set manually. All <code>SimpleBigDecimal</code>s
|
||||
* taking part in the same arithmetic operation must have equal scale. The
|
||||
* result of a multiplication of two <code>SimpleBigDecimal</code>s returns a
|
||||
* <code>SimpleBigDecimal</code> with double scale.
|
||||
*/
|
||||
class SimpleBigDecimal
|
||||
//extends Number // not in J2ME - add compatibility class?
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final BigInteger bigInt;
|
||||
private final int scale;
|
||||
|
||||
/**
|
||||
* Returns a <code>SimpleBigDecimal</code> representing the same numerical
|
||||
* value as <code>value</code>.
|
||||
* @param value The value of the <code>SimpleBigDecimal</code> to be
|
||||
* created.
|
||||
* @param scale The scale of the <code>SimpleBigDecimal</code> to be
|
||||
* created.
|
||||
* @return The such created <code>SimpleBigDecimal</code>.
|
||||
*/
|
||||
public static SimpleBigDecimal getInstance(BigInteger value, int scale)
|
||||
{
|
||||
return new SimpleBigDecimal(value.shiftLeft(scale), scale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for <code>SimpleBigDecimal</code>. The value of the
|
||||
* constructed <code>SimpleBigDecimal</code> equals <code>bigInt /
|
||||
* 2<sup>scale</sup></code>.
|
||||
* @param bigInt The <code>bigInt</code> value parameter.
|
||||
* @param scale The scale of the constructed <code>SimpleBigDecimal</code>.
|
||||
*/
|
||||
public SimpleBigDecimal(BigInteger bigInt, int scale)
|
||||
{
|
||||
if (scale < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("scale may not be negative");
|
||||
}
|
||||
|
||||
this.bigInt = bigInt;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
private SimpleBigDecimal(SimpleBigDecimal limBigDec)
|
||||
{
|
||||
bigInt = limBigDec.bigInt;
|
||||
scale = limBigDec.scale;
|
||||
}
|
||||
|
||||
private void checkScale(SimpleBigDecimal b)
|
||||
{
|
||||
if (scale != b.scale)
|
||||
{
|
||||
throw new IllegalArgumentException("Only SimpleBigDecimal of " +
|
||||
"same scale allowed in arithmetic operations");
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleBigDecimal adjustScale(int newScale)
|
||||
{
|
||||
if (newScale < 0)
|
||||
{
|
||||
throw new IllegalArgumentException("scale may not be negative");
|
||||
}
|
||||
|
||||
if (newScale == scale)
|
||||
{
|
||||
return new SimpleBigDecimal(this);
|
||||
}
|
||||
|
||||
return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),
|
||||
newScale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal add(SimpleBigDecimal b)
|
||||
{
|
||||
checkScale(b);
|
||||
return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal add(BigInteger b)
|
||||
{
|
||||
return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal negate()
|
||||
{
|
||||
return new SimpleBigDecimal(bigInt.negate(), scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal subtract(SimpleBigDecimal b)
|
||||
{
|
||||
return add(b.negate());
|
||||
}
|
||||
|
||||
public SimpleBigDecimal subtract(BigInteger b)
|
||||
{
|
||||
return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)),
|
||||
scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal multiply(SimpleBigDecimal b)
|
||||
{
|
||||
checkScale(b);
|
||||
return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal multiply(BigInteger b)
|
||||
{
|
||||
return new SimpleBigDecimal(bigInt.multiply(b), scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal divide(SimpleBigDecimal b)
|
||||
{
|
||||
checkScale(b);
|
||||
BigInteger dividend = bigInt.shiftLeft(scale);
|
||||
return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal divide(BigInteger b)
|
||||
{
|
||||
return new SimpleBigDecimal(bigInt.divide(b), scale);
|
||||
}
|
||||
|
||||
public SimpleBigDecimal shiftLeft(int n)
|
||||
{
|
||||
return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);
|
||||
}
|
||||
|
||||
public int compareTo(SimpleBigDecimal val)
|
||||
{
|
||||
checkScale(val);
|
||||
return bigInt.compareTo(val.bigInt);
|
||||
}
|
||||
|
||||
public int compareTo(BigInteger val)
|
||||
{
|
||||
return bigInt.compareTo(val.shiftLeft(scale));
|
||||
}
|
||||
|
||||
public BigInteger floor()
|
||||
{
|
||||
return bigInt.shiftRight(scale);
|
||||
}
|
||||
|
||||
public BigInteger round()
|
||||
{
|
||||
SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1);
|
||||
return add(oneHalf.adjustScale(scale)).floor();
|
||||
}
|
||||
|
||||
public int intValue()
|
||||
{
|
||||
return floor().intValue();
|
||||
}
|
||||
|
||||
public long longValue()
|
||||
{
|
||||
return floor().longValue();
|
||||
}
|
||||
/* NON-J2ME compliant.
|
||||
public double doubleValue()
|
||||
{
|
||||
return Double.valueOf(toString()).doubleValue();
|
||||
}
|
||||
|
||||
public float floatValue()
|
||||
{
|
||||
return Float.valueOf(toString()).floatValue();
|
||||
}
|
||||
*/
|
||||
public int getScale()
|
||||
{
|
||||
return scale;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
if (scale == 0)
|
||||
{
|
||||
return bigInt.toString();
|
||||
}
|
||||
|
||||
BigInteger floorBigInt = floor();
|
||||
|
||||
BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale));
|
||||
if (bigInt.signum() == -1)
|
||||
{
|
||||
fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);
|
||||
}
|
||||
|
||||
if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO))))
|
||||
{
|
||||
floorBigInt = floorBigInt.add(ECConstants.ONE);
|
||||
}
|
||||
String leftOfPoint = floorBigInt.toString();
|
||||
|
||||
char[] fractCharArr = new char[scale];
|
||||
String fractStr = fract.toString(2);
|
||||
int fractLen = fractStr.length();
|
||||
int zeroes = scale - fractLen;
|
||||
for (int i = 0; i < zeroes; i++)
|
||||
{
|
||||
fractCharArr[i] = '0';
|
||||
}
|
||||
for (int j = 0; j < fractLen; j++)
|
||||
{
|
||||
fractCharArr[zeroes + j] = fractStr.charAt(j);
|
||||
}
|
||||
String rightOfPoint = new String(fractCharArr);
|
||||
|
||||
StringBuffer sb = new StringBuffer(leftOfPoint);
|
||||
sb.append(".");
|
||||
sb.append(rightOfPoint);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof SimpleBigDecimal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SimpleBigDecimal other = (SimpleBigDecimal)o;
|
||||
return ((bigInt.equals(other.bigInt)) && (scale == other.scale));
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return bigInt.hashCode() ^ scale;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,844 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Class holding methods for point multiplication based on the window
|
||||
* τ-adic nonadjacent form (WTNAF). The algorithms are based on the
|
||||
* paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
|
||||
* by Jerome A. Solinas. The paper first appeared in the Proceedings of
|
||||
* Crypto 1997.
|
||||
*/
|
||||
class Tnaf
|
||||
{
|
||||
private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();
|
||||
private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();
|
||||
private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();
|
||||
|
||||
/**
|
||||
* The window width of WTNAF. The standard value of 4 is slightly less
|
||||
* than optimal for running time, but keeps space requirements for
|
||||
* precomputation low. For typical curves, a value of 5 or 6 results in
|
||||
* a better running time. When changing this value, the
|
||||
* <code>α<sub>u</sub></code>'s must be computed differently, see
|
||||
* e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
|
||||
* Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
|
||||
* p. 121-122
|
||||
*/
|
||||
public static final byte WIDTH = 4;
|
||||
|
||||
/**
|
||||
* 2<sup>4</sup>
|
||||
*/
|
||||
public static final byte POW_2_WIDTH = 16;
|
||||
|
||||
/**
|
||||
* The <code>α<sub>u</sub></code>'s for <code>a=0</code> as an array
|
||||
* of <code>ZTauElement</code>s.
|
||||
*/
|
||||
public static final ZTauElement[] alpha0 = {
|
||||
null,
|
||||
new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
|
||||
new ZTauElement(MINUS_THREE, MINUS_ONE), null,
|
||||
new ZTauElement(MINUS_ONE, MINUS_ONE), null,
|
||||
new ZTauElement(ECConstants.ONE, MINUS_ONE), null
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>α<sub>u</sub></code>'s for <code>a=0</code> as an array
|
||||
* of TNAFs.
|
||||
*/
|
||||
public static final byte[][] alpha0Tnaf = {
|
||||
null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>α<sub>u</sub></code>'s for <code>a=1</code> as an array
|
||||
* of <code>ZTauElement</code>s.
|
||||
*/
|
||||
public static final ZTauElement[] alpha1 = {null,
|
||||
new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
|
||||
new ZTauElement(MINUS_THREE, ECConstants.ONE), null,
|
||||
new ZTauElement(MINUS_ONE, ECConstants.ONE), null,
|
||||
new ZTauElement(ECConstants.ONE, ECConstants.ONE), null
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>α<sub>u</sub></code>'s for <code>a=1</code> as an array
|
||||
* of TNAFs.
|
||||
*/
|
||||
public static final byte[][] alpha1Tnaf = {
|
||||
null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes the norm of an element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code>.
|
||||
* @param mu The parameter <code>μ</code> of the elliptic curve.
|
||||
* @param lambda The element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code>.
|
||||
* @return The norm of <code>λ</code>.
|
||||
*/
|
||||
public static BigInteger norm(final byte mu, ZTauElement lambda)
|
||||
{
|
||||
BigInteger norm;
|
||||
|
||||
// s1 = u^2
|
||||
BigInteger s1 = lambda.u.multiply(lambda.u);
|
||||
|
||||
// s2 = u * v
|
||||
BigInteger s2 = lambda.u.multiply(lambda.v);
|
||||
|
||||
// s3 = 2 * v^2
|
||||
BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);
|
||||
|
||||
if (mu == 1)
|
||||
{
|
||||
norm = s1.add(s2).add(s3);
|
||||
}
|
||||
else if (mu == -1)
|
||||
{
|
||||
norm = s1.subtract(s2).add(s3);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the norm of an element <code>λ</code> of
|
||||
* <code><b>R</b>[τ]</code>, where <code>λ = u + vτ</code>
|
||||
* and <code>u</code> and <code>u</code> are real numbers (elements of
|
||||
* <code><b>R</b></code>).
|
||||
* @param mu The parameter <code>μ</code> of the elliptic curve.
|
||||
* @param u The real part of the element <code>λ</code> of
|
||||
* <code><b>R</b>[τ]</code>.
|
||||
* @param v The <code>τ</code>-adic part of the element
|
||||
* <code>λ</code> of <code><b>R</b>[τ]</code>.
|
||||
* @return The norm of <code>λ</code>.
|
||||
*/
|
||||
public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,
|
||||
SimpleBigDecimal v)
|
||||
{
|
||||
SimpleBigDecimal norm;
|
||||
|
||||
// s1 = u^2
|
||||
SimpleBigDecimal s1 = u.multiply(u);
|
||||
|
||||
// s2 = u * v
|
||||
SimpleBigDecimal s2 = u.multiply(v);
|
||||
|
||||
// s3 = 2 * v^2
|
||||
SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);
|
||||
|
||||
if (mu == 1)
|
||||
{
|
||||
norm = s1.add(s2).add(s3);
|
||||
}
|
||||
else if (mu == -1)
|
||||
{
|
||||
norm = s1.subtract(s2).add(s3);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
return norm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds an element <code>λ</code> of <code><b>R</b>[τ]</code>
|
||||
* to an element of <code><b>Z</b>[τ]</code>, such that their difference
|
||||
* has minimal norm. <code>λ</code> is given as
|
||||
* <code>λ = λ<sub>0</sub> + λ<sub>1</sub>τ</code>.
|
||||
* @param lambda0 The component <code>λ<sub>0</sub></code>.
|
||||
* @param lambda1 The component <code>λ<sub>1</sub></code>.
|
||||
* @param mu The parameter <code>μ</code> of the elliptic curve. Must
|
||||
* equal 1 or -1.
|
||||
* @return The rounded element of <code><b>Z</b>[τ]</code>.
|
||||
* @throws IllegalArgumentException if <code>lambda0</code> and
|
||||
* <code>lambda1</code> do not have same scale.
|
||||
*/
|
||||
public static ZTauElement round(SimpleBigDecimal lambda0,
|
||||
SimpleBigDecimal lambda1, byte mu)
|
||||
{
|
||||
int scale = lambda0.getScale();
|
||||
if (lambda1.getScale() != scale)
|
||||
{
|
||||
throw new IllegalArgumentException("lambda0 and lambda1 do not " +
|
||||
"have same scale");
|
||||
}
|
||||
|
||||
if (!((mu == 1) || (mu == -1)))
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
BigInteger f0 = lambda0.round();
|
||||
BigInteger f1 = lambda1.round();
|
||||
|
||||
SimpleBigDecimal eta0 = lambda0.subtract(f0);
|
||||
SimpleBigDecimal eta1 = lambda1.subtract(f1);
|
||||
|
||||
// eta = 2*eta0 + mu*eta1
|
||||
SimpleBigDecimal eta = eta0.add(eta0);
|
||||
if (mu == 1)
|
||||
{
|
||||
eta = eta.add(eta1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mu == -1
|
||||
eta = eta.subtract(eta1);
|
||||
}
|
||||
|
||||
// check1 = eta0 - 3*mu*eta1
|
||||
// check2 = eta0 + 4*mu*eta1
|
||||
SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);
|
||||
SimpleBigDecimal fourEta1 = threeEta1.add(eta1);
|
||||
SimpleBigDecimal check1;
|
||||
SimpleBigDecimal check2;
|
||||
if (mu == 1)
|
||||
{
|
||||
check1 = eta0.subtract(threeEta1);
|
||||
check2 = eta0.add(fourEta1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mu == -1
|
||||
check1 = eta0.add(threeEta1);
|
||||
check2 = eta0.subtract(fourEta1);
|
||||
}
|
||||
|
||||
byte h0 = 0;
|
||||
byte h1 = 0;
|
||||
|
||||
// if eta >= 1
|
||||
if (eta.compareTo(ECConstants.ONE) >= 0)
|
||||
{
|
||||
if (check1.compareTo(MINUS_ONE) < 0)
|
||||
{
|
||||
h1 = mu;
|
||||
}
|
||||
else
|
||||
{
|
||||
h0 = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// eta < 1
|
||||
if (check2.compareTo(ECConstants.TWO) >= 0)
|
||||
{
|
||||
h1 = mu;
|
||||
}
|
||||
}
|
||||
|
||||
// if eta < -1
|
||||
if (eta.compareTo(MINUS_ONE) < 0)
|
||||
{
|
||||
if (check1.compareTo(ECConstants.ONE) >= 0)
|
||||
{
|
||||
h1 = (byte)-mu;
|
||||
}
|
||||
else
|
||||
{
|
||||
h0 = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// eta >= -1
|
||||
if (check2.compareTo(MINUS_TWO) < 0)
|
||||
{
|
||||
h1 = (byte)-mu;
|
||||
}
|
||||
}
|
||||
|
||||
BigInteger q0 = f0.add(BigInteger.valueOf(h0));
|
||||
BigInteger q1 = f1.add(BigInteger.valueOf(h1));
|
||||
return new ZTauElement(q0, q1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approximate division by <code>n</code>. For an integer
|
||||
* <code>k</code>, the value <code>λ = s k / n</code> is
|
||||
* computed to <code>c</code> bits of accuracy.
|
||||
* @param k The parameter <code>k</code>.
|
||||
* @param s The curve parameter <code>s<sub>0</sub></code> or
|
||||
* <code>s<sub>1</sub></code>.
|
||||
* @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
|
||||
* @param a The parameter <code>a</code> of the elliptic curve.
|
||||
* @param m The bit length of the finite field
|
||||
* <code><b>F</b><sub>m</sub></code>.
|
||||
* @param c The number of bits of accuracy, i.e. the scale of the returned
|
||||
* <code>SimpleBigDecimal</code>.
|
||||
* @return The value <code>λ = s k / n</code> computed to
|
||||
* <code>c</code> bits of accuracy.
|
||||
*/
|
||||
public static SimpleBigDecimal approximateDivisionByN(BigInteger k,
|
||||
BigInteger s, BigInteger vm, byte a, int m, int c)
|
||||
{
|
||||
int _k = (m + 5)/2 + c;
|
||||
BigInteger ns = k.shiftRight(m - _k - 2 + a);
|
||||
|
||||
BigInteger gs = s.multiply(ns);
|
||||
|
||||
BigInteger hs = gs.shiftRight(m);
|
||||
|
||||
BigInteger js = vm.multiply(hs);
|
||||
|
||||
BigInteger gsPlusJs = gs.add(js);
|
||||
BigInteger ls = gsPlusJs.shiftRight(_k-c);
|
||||
if (gsPlusJs.testBit(_k-c-1))
|
||||
{
|
||||
// round up
|
||||
ls = ls.add(ECConstants.ONE);
|
||||
}
|
||||
|
||||
return new SimpleBigDecimal(ls, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the <code>τ</code>-adic NAF (non-adjacent form) of an
|
||||
* element <code>λ</code> of <code><b>Z</b>[τ]</code>.
|
||||
* @param mu The parameter <code>μ</code> of the elliptic curve.
|
||||
* @param lambda The element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code>.
|
||||
* @return The <code>τ</code>-adic NAF of <code>λ</code>.
|
||||
*/
|
||||
public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)
|
||||
{
|
||||
if (!((mu == 1) || (mu == -1)))
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
BigInteger norm = norm(mu, lambda);
|
||||
|
||||
// Ceiling of log2 of the norm
|
||||
int log2Norm = norm.bitLength();
|
||||
|
||||
// If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
|
||||
int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
|
||||
|
||||
// The array holding the TNAF
|
||||
byte[] u = new byte[maxLength];
|
||||
int i = 0;
|
||||
|
||||
// The actual length of the TNAF
|
||||
int length = 0;
|
||||
|
||||
BigInteger r0 = lambda.u;
|
||||
BigInteger r1 = lambda.v;
|
||||
|
||||
while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))
|
||||
{
|
||||
// If r0 is odd
|
||||
if (r0.testBit(0))
|
||||
{
|
||||
u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();
|
||||
|
||||
// r0 = r0 - u[i]
|
||||
if (u[i] == 1)
|
||||
{
|
||||
r0 = r0.clearBit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// u[i] == -1
|
||||
r0 = r0.add(ECConstants.ONE);
|
||||
}
|
||||
length = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
u[i] = 0;
|
||||
}
|
||||
|
||||
BigInteger t = r0;
|
||||
BigInteger s = r0.shiftRight(1);
|
||||
if (mu == 1)
|
||||
{
|
||||
r0 = r1.add(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mu == -1
|
||||
r0 = r1.subtract(s);
|
||||
}
|
||||
|
||||
r1 = t.shiftRight(1).negate();
|
||||
i++;
|
||||
}
|
||||
|
||||
length++;
|
||||
|
||||
// Reduce the TNAF array to its actual length
|
||||
byte[] tnaf = new byte[length];
|
||||
System.arraycopy(u, 0, tnaf, 0, length);
|
||||
return tnaf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the operation <code>τ()</code> to an
|
||||
* <code>ECPoint.F2m</code>.
|
||||
* @param p The ECPoint.F2m to which <code>τ()</code> is applied.
|
||||
* @return <code>τ(p)</code>
|
||||
*/
|
||||
public static ECPoint.F2m tau(ECPoint.F2m p)
|
||||
{
|
||||
if (p.isInfinity())
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
ECFieldElement x = p.getX();
|
||||
ECFieldElement y = p.getY();
|
||||
|
||||
return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameter <code>μ</code> of the elliptic curve.
|
||||
* @param curve The elliptic curve from which to obtain <code>μ</code>.
|
||||
* The curve must be a Koblitz curve, i.e. <code>a</code> equals
|
||||
* <code>0</code> or <code>1</code> and <code>b</code> equals
|
||||
* <code>1</code>.
|
||||
* @return <code>μ</code> of the elliptic curve.
|
||||
* @throws IllegalArgumentException if the given ECCurve is not a Koblitz
|
||||
* curve.
|
||||
*/
|
||||
public static byte getMu(ECCurve.F2m curve)
|
||||
{
|
||||
BigInteger a = curve.getA().toBigInteger();
|
||||
byte mu;
|
||||
|
||||
if (a.equals(ECConstants.ZERO))
|
||||
{
|
||||
mu = -1;
|
||||
}
|
||||
else if (a.equals(ECConstants.ONE))
|
||||
{
|
||||
mu = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("No Koblitz curve (ABC), " +
|
||||
"TNAF multiplication not possible");
|
||||
}
|
||||
return mu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
|
||||
* <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
|
||||
* <code>V<sub>k</sub></code>.
|
||||
* @param mu The parameter <code>μ</code> of the elliptic curve.
|
||||
* @param k The index of the second element of the Lucas Sequence to be
|
||||
* returned.
|
||||
* @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
|
||||
* <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
|
||||
* <code>U<sub>k</sub></code>.
|
||||
* @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
|
||||
* and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
|
||||
* and <code>V<sub>k</sub></code>.
|
||||
*/
|
||||
public static BigInteger[] getLucas(byte mu, int k, boolean doV)
|
||||
{
|
||||
if (!((mu == 1) || (mu == -1)))
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
BigInteger u0;
|
||||
BigInteger u1;
|
||||
BigInteger u2;
|
||||
|
||||
if (doV)
|
||||
{
|
||||
u0 = ECConstants.TWO;
|
||||
u1 = BigInteger.valueOf(mu);
|
||||
}
|
||||
else
|
||||
{
|
||||
u0 = ECConstants.ZERO;
|
||||
u1 = ECConstants.ONE;
|
||||
}
|
||||
|
||||
for (int i = 1; i < k; i++)
|
||||
{
|
||||
// u2 = mu*u1 - 2*u0;
|
||||
BigInteger s = null;
|
||||
if (mu == 1)
|
||||
{
|
||||
s = u1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// mu == -1
|
||||
s = u1.negate();
|
||||
}
|
||||
|
||||
u2 = s.subtract(u0.shiftLeft(1));
|
||||
u0 = u1;
|
||||
u1 = u2;
|
||||
// System.out.println(i + ": " + u2);
|
||||
// System.out.println();
|
||||
}
|
||||
|
||||
BigInteger[] retVal = {u0, u1};
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
|
||||
* 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
|
||||
* <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code>
|
||||
* @param mu The parameter <code>μ</code> of the elliptic curve.
|
||||
* @param w The window width of the WTNAF.
|
||||
* @return the auxiliary value <code>t<sub>w</sub></code>
|
||||
*/
|
||||
public static BigInteger getTw(byte mu, int w)
|
||||
{
|
||||
if (w == 4)
|
||||
{
|
||||
if (mu == 1)
|
||||
{
|
||||
return BigInteger.valueOf(6);
|
||||
}
|
||||
else
|
||||
{
|
||||
// mu == -1
|
||||
return BigInteger.valueOf(10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For w <> 4, the values must be computed
|
||||
BigInteger[] us = getLucas(mu, w, false);
|
||||
BigInteger twoToW = ECConstants.ZERO.setBit(w);
|
||||
BigInteger u1invert = us[1].modInverse(twoToW);
|
||||
BigInteger tw;
|
||||
tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);
|
||||
// System.out.println("mu = " + mu);
|
||||
// System.out.println("tw = " + tw);
|
||||
return tw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the auxiliary values <code>s<sub>0</sub></code> and
|
||||
* <code>s<sub>1</sub></code> used for partial modular reduction.
|
||||
* @param curve The elliptic curve for which to compute
|
||||
* <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
|
||||
* @throws IllegalArgumentException if <code>curve</code> is not a
|
||||
* Koblitz curve (Anomalous Binary Curve, ABC).
|
||||
*/
|
||||
public static BigInteger[] getSi(ECCurve.F2m curve)
|
||||
{
|
||||
if (!curve.isKoblitz())
|
||||
{
|
||||
throw new IllegalArgumentException("si is defined for Koblitz curves only");
|
||||
}
|
||||
|
||||
int m = curve.getM();
|
||||
int a = curve.getA().toBigInteger().intValue();
|
||||
byte mu = curve.getMu();
|
||||
int h = curve.getH().intValue();
|
||||
int index = m + 3 - a;
|
||||
BigInteger[] ui = getLucas(mu, index, false);
|
||||
|
||||
BigInteger dividend0;
|
||||
BigInteger dividend1;
|
||||
if (mu == 1)
|
||||
{
|
||||
dividend0 = ECConstants.ONE.subtract(ui[1]);
|
||||
dividend1 = ECConstants.ONE.subtract(ui[0]);
|
||||
}
|
||||
else if (mu == -1)
|
||||
{
|
||||
dividend0 = ECConstants.ONE.add(ui[1]);
|
||||
dividend1 = ECConstants.ONE.add(ui[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
BigInteger[] si = new BigInteger[2];
|
||||
|
||||
if (h == 2)
|
||||
{
|
||||
si[0] = dividend0.shiftRight(1);
|
||||
si[1] = dividend1.shiftRight(1).negate();
|
||||
}
|
||||
else if (h == 4)
|
||||
{
|
||||
si[0] = dividend0.shiftRight(2);
|
||||
si[1] = dividend1.shiftRight(2).negate();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("h (Cofactor) must be 2 or 4");
|
||||
}
|
||||
|
||||
return si;
|
||||
}
|
||||
|
||||
/**
|
||||
* Partial modular reduction modulo
|
||||
* <code>(τ<sup>m</sup> - 1)/(τ - 1)</code>.
|
||||
* @param k The integer to be reduced.
|
||||
* @param m The bitlength of the underlying finite field.
|
||||
* @param a The parameter <code>a</code> of the elliptic curve.
|
||||
* @param s The auxiliary values <code>s<sub>0</sub></code> and
|
||||
* <code>s<sub>1</sub></code>.
|
||||
* @param mu The parameter μ of the elliptic curve.
|
||||
* @param c The precision (number of bits of accuracy) of the partial
|
||||
* modular reduction.
|
||||
* @return <code>ρ := k partmod (τ<sup>m</sup> - 1)/(τ - 1)</code>
|
||||
*/
|
||||
public static ZTauElement partModReduction(BigInteger k, int m, byte a,
|
||||
BigInteger[] s, byte mu, byte c)
|
||||
{
|
||||
// d0 = s[0] + mu*s[1]; mu is either 1 or -1
|
||||
BigInteger d0;
|
||||
if (mu == 1)
|
||||
{
|
||||
d0 = s[0].add(s[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
d0 = s[0].subtract(s[1]);
|
||||
}
|
||||
|
||||
BigInteger[] v = getLucas(mu, m, true);
|
||||
BigInteger vm = v[1];
|
||||
|
||||
SimpleBigDecimal lambda0 = approximateDivisionByN(
|
||||
k, s[0], vm, a, m, c);
|
||||
|
||||
SimpleBigDecimal lambda1 = approximateDivisionByN(
|
||||
k, s[1], vm, a, m, c);
|
||||
|
||||
ZTauElement q = round(lambda0, lambda1, mu);
|
||||
|
||||
// r0 = n - d0*q0 - 2*s1*q1
|
||||
BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(
|
||||
BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));
|
||||
|
||||
// r1 = s1*q0 - s0*q1
|
||||
BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));
|
||||
|
||||
return new ZTauElement(r0, r1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
|
||||
* by a <code>BigInteger</code> using the reduced <code>τ</code>-adic
|
||||
* NAF (RTNAF) method.
|
||||
* @param p The ECPoint.F2m to multiply.
|
||||
* @param k The <code>BigInteger</code> by which to multiply <code>p</code>.
|
||||
* @return <code>k * p</code>
|
||||
*/
|
||||
public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m p, BigInteger k)
|
||||
{
|
||||
ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
|
||||
int m = curve.getM();
|
||||
byte a = (byte) curve.getA().toBigInteger().intValue();
|
||||
byte mu = curve.getMu();
|
||||
BigInteger[] s = curve.getSi();
|
||||
ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10);
|
||||
|
||||
return multiplyTnaf(p, rho);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
|
||||
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
|
||||
* using the <code>τ</code>-adic NAF (TNAF) method.
|
||||
* @param p The ECPoint.F2m to multiply.
|
||||
* @param lambda The element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code>.
|
||||
* @return <code>λ * p</code>
|
||||
*/
|
||||
public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda)
|
||||
{
|
||||
ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
|
||||
byte mu = curve.getMu();
|
||||
byte[] u = tauAdicNaf(mu, lambda);
|
||||
|
||||
ECPoint.F2m q = multiplyFromTnaf(p, u);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
|
||||
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
|
||||
* using the <code>τ</code>-adic NAF (TNAF) method, given the TNAF
|
||||
* of <code>λ</code>.
|
||||
* @param p The ECPoint.F2m to multiply.
|
||||
* @param u The the TNAF of <code>λ</code>..
|
||||
* @return <code>λ * p</code>
|
||||
*/
|
||||
public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u)
|
||||
{
|
||||
ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
|
||||
ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity();
|
||||
for (int i = u.length - 1; i >= 0; i--)
|
||||
{
|
||||
q = tau(q);
|
||||
if (u[i] == 1)
|
||||
{
|
||||
q = (ECPoint.F2m)q.addSimple(p);
|
||||
}
|
||||
else if (u[i] == -1)
|
||||
{
|
||||
q = (ECPoint.F2m)q.subtractSimple(p);
|
||||
}
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the <code>[τ]</code>-adic window NAF of an element
|
||||
* <code>λ</code> of <code><b>Z</b>[τ]</code>.
|
||||
* @param mu The parameter μ of the elliptic curve.
|
||||
* @param lambda The element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code> of which to compute the
|
||||
* <code>[τ]</code>-adic NAF.
|
||||
* @param width The window width of the resulting WNAF.
|
||||
* @param pow2w 2<sup>width</sup>.
|
||||
* @param tw The auxiliary value <code>t<sub>w</sub></code>.
|
||||
* @param alpha The <code>α<sub>u</sub></code>'s for the window width.
|
||||
* @return The <code>[τ]</code>-adic window NAF of
|
||||
* <code>λ</code>.
|
||||
*/
|
||||
public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,
|
||||
byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
|
||||
{
|
||||
if (!((mu == 1) || (mu == -1)))
|
||||
{
|
||||
throw new IllegalArgumentException("mu must be 1 or -1");
|
||||
}
|
||||
|
||||
BigInteger norm = norm(mu, lambda);
|
||||
|
||||
// Ceiling of log2 of the norm
|
||||
int log2Norm = norm.bitLength();
|
||||
|
||||
// If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
|
||||
int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
|
||||
|
||||
// The array holding the TNAF
|
||||
byte[] u = new byte[maxLength];
|
||||
|
||||
// 2^(width - 1)
|
||||
BigInteger pow2wMin1 = pow2w.shiftRight(1);
|
||||
|
||||
// Split lambda into two BigIntegers to simplify calculations
|
||||
BigInteger r0 = lambda.u;
|
||||
BigInteger r1 = lambda.v;
|
||||
int i = 0;
|
||||
|
||||
// while lambda <> (0, 0)
|
||||
while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))
|
||||
{
|
||||
// if r0 is odd
|
||||
if (r0.testBit(0))
|
||||
{
|
||||
// uUnMod = r0 + r1*tw mod 2^width
|
||||
BigInteger uUnMod
|
||||
= r0.add(r1.multiply(tw)).mod(pow2w);
|
||||
|
||||
byte uLocal;
|
||||
// if uUnMod >= 2^(width - 1)
|
||||
if (uUnMod.compareTo(pow2wMin1) >= 0)
|
||||
{
|
||||
uLocal = (byte) uUnMod.subtract(pow2w).intValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
uLocal = (byte) uUnMod.intValue();
|
||||
}
|
||||
// uLocal is now in [-2^(width-1), 2^(width-1)-1]
|
||||
|
||||
u[i] = uLocal;
|
||||
boolean s = true;
|
||||
if (uLocal < 0)
|
||||
{
|
||||
s = false;
|
||||
uLocal = (byte)-uLocal;
|
||||
}
|
||||
// uLocal is now >= 0
|
||||
|
||||
if (s)
|
||||
{
|
||||
r0 = r0.subtract(alpha[uLocal].u);
|
||||
r1 = r1.subtract(alpha[uLocal].v);
|
||||
}
|
||||
else
|
||||
{
|
||||
r0 = r0.add(alpha[uLocal].u);
|
||||
r1 = r1.add(alpha[uLocal].v);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
u[i] = 0;
|
||||
}
|
||||
|
||||
BigInteger t = r0;
|
||||
|
||||
if (mu == 1)
|
||||
{
|
||||
r0 = r1.add(r0.shiftRight(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
// mu == -1
|
||||
r0 = r1.subtract(r0.shiftRight(1));
|
||||
}
|
||||
r1 = t.shiftRight(1).negate();
|
||||
i++;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the precomputation for WTNAF multiplication.
|
||||
* @param p The <code>ECPoint</code> for which to do the precomputation.
|
||||
* @param a The parameter <code>a</code> of the elliptic curve.
|
||||
* @return The precomputation array for <code>p</code>.
|
||||
*/
|
||||
public static ECPoint.F2m[] getPreComp(ECPoint.F2m p, byte a)
|
||||
{
|
||||
ECPoint.F2m[] pu;
|
||||
pu = new ECPoint.F2m[16];
|
||||
pu[1] = p;
|
||||
byte[][] alphaTnaf;
|
||||
if (a == 0)
|
||||
{
|
||||
alphaTnaf = Tnaf.alpha0Tnaf;
|
||||
}
|
||||
else
|
||||
{
|
||||
// a == 1
|
||||
alphaTnaf = Tnaf.alpha1Tnaf;
|
||||
}
|
||||
|
||||
int precompLen = alphaTnaf.length;
|
||||
for (int i = 3; i < precompLen; i = i + 2)
|
||||
{
|
||||
pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
|
||||
}
|
||||
|
||||
return pu;
|
||||
}
|
||||
}
|
|
@ -1,240 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Class implementing the WNAF (Window Non-Adjacent Form) multiplication
|
||||
* algorithm.
|
||||
*/
|
||||
class WNafMultiplier implements ECMultiplier
|
||||
{
|
||||
/**
|
||||
* Computes the Window NAF (non-adjacent Form) of an integer.
|
||||
* @param width The width <code>w</code> of the Window NAF. The width is
|
||||
* defined as the minimal number <code>w</code>, such that for any
|
||||
* <code>w</code> consecutive digits in the resulting representation, at
|
||||
* most one is non-zero.
|
||||
* @param k The integer of which the Window NAF is computed.
|
||||
* @return The Window NAF of the given width, such that the following holds:
|
||||
* <code>k = ∑<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
|
||||
* </code>, where the <code>k<sub>i</sub></code> denote the elements of the
|
||||
* returned <code>byte[]</code>.
|
||||
*/
|
||||
public byte[] windowNaf(byte width, BigInteger k)
|
||||
{
|
||||
// The window NAF is at most 1 element longer than the binary
|
||||
// representation of the integer k. byte can be used instead of short or
|
||||
// int unless the window width is larger than 8. For larger width use
|
||||
// short or int. However, a width of more than 8 is not efficient for
|
||||
// m = log2(q) smaller than 2305 Bits. Note: Values for m larger than
|
||||
// 1000 Bits are currently not used in practice.
|
||||
byte[] wnaf = new byte[k.bitLength() + 1];
|
||||
|
||||
// 2^width as short and BigInteger
|
||||
short pow2wB = (short)(1 << width);
|
||||
BigInteger pow2wBI = BigInteger.valueOf(pow2wB);
|
||||
|
||||
int i = 0;
|
||||
|
||||
// The actual length of the WNAF
|
||||
int length = 0;
|
||||
|
||||
// while k >= 1
|
||||
while (k.signum() > 0)
|
||||
{
|
||||
// if k is odd
|
||||
if (k.testBit(0))
|
||||
{
|
||||
// k mod 2^width
|
||||
BigInteger remainder = k.mod(pow2wBI);
|
||||
|
||||
// if remainder > 2^(width - 1) - 1
|
||||
if (remainder.testBit(width - 1))
|
||||
{
|
||||
wnaf[i] = (byte)(remainder.intValue() - pow2wB);
|
||||
}
|
||||
else
|
||||
{
|
||||
wnaf[i] = (byte)remainder.intValue();
|
||||
}
|
||||
// wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]
|
||||
|
||||
k = k.subtract(BigInteger.valueOf(wnaf[i]));
|
||||
length = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
wnaf[i] = 0;
|
||||
}
|
||||
|
||||
// k = k/2
|
||||
k = k.shiftRight(1);
|
||||
i++;
|
||||
}
|
||||
|
||||
length++;
|
||||
|
||||
// Reduce the WNAF array to its actual length
|
||||
byte[] wnafShort = new byte[length];
|
||||
System.arraycopy(wnaf, 0, wnafShort, 0, length);
|
||||
return wnafShort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies <code>this</code> by an integer <code>k</code> using the
|
||||
* Window NAF method.
|
||||
* @param k The integer by which <code>this</code> is multiplied.
|
||||
* @return A new <code>ECPoint</code> which equals <code>this</code>
|
||||
* multiplied by <code>k</code>.
|
||||
*/
|
||||
public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
|
||||
{
|
||||
WNafPreCompInfo wnafPreCompInfo;
|
||||
|
||||
if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
|
||||
{
|
||||
wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore empty PreCompInfo or PreCompInfo of incorrect type
|
||||
wnafPreCompInfo = new WNafPreCompInfo();
|
||||
}
|
||||
|
||||
// floor(log2(k))
|
||||
int m = k.bitLength();
|
||||
|
||||
// width of the Window NAF
|
||||
byte width;
|
||||
|
||||
// Required length of precomputation array
|
||||
int reqPreCompLen;
|
||||
|
||||
// Determine optimal width and corresponding length of precomputation
|
||||
// array based on literature values
|
||||
if (m < 13)
|
||||
{
|
||||
width = 2;
|
||||
reqPreCompLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m < 41)
|
||||
{
|
||||
width = 3;
|
||||
reqPreCompLen = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m < 121)
|
||||
{
|
||||
width = 4;
|
||||
reqPreCompLen = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m < 337)
|
||||
{
|
||||
width = 5;
|
||||
reqPreCompLen = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m < 897)
|
||||
{
|
||||
width = 6;
|
||||
reqPreCompLen = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m < 2305)
|
||||
{
|
||||
width = 7;
|
||||
reqPreCompLen = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 8;
|
||||
reqPreCompLen = 127;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The length of the precomputation array
|
||||
int preCompLen = 1;
|
||||
|
||||
ECPoint[] preComp = wnafPreCompInfo.getPreComp();
|
||||
ECPoint twiceP = wnafPreCompInfo.getTwiceP();
|
||||
|
||||
// Check if the precomputed ECPoints already exist
|
||||
if (preComp == null)
|
||||
{
|
||||
// Precomputation must be performed from scratch, create an empty
|
||||
// precomputation array of desired length
|
||||
preComp = new ECPoint[]{ p };
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take the already precomputed ECPoints to start with
|
||||
preCompLen = preComp.length;
|
||||
}
|
||||
|
||||
if (twiceP == null)
|
||||
{
|
||||
// Compute twice(p)
|
||||
twiceP = p.twice();
|
||||
}
|
||||
|
||||
if (preCompLen < reqPreCompLen)
|
||||
{
|
||||
// Precomputation array must be made bigger, copy existing preComp
|
||||
// array into the larger new preComp array
|
||||
ECPoint[] oldPreComp = preComp;
|
||||
preComp = new ECPoint[reqPreCompLen];
|
||||
System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen);
|
||||
|
||||
for (int i = preCompLen; i < reqPreCompLen; i++)
|
||||
{
|
||||
// Compute the new ECPoints for the precomputation array.
|
||||
// The values 1, 3, 5, ..., 2^(width-1)-1 times p are
|
||||
// computed
|
||||
preComp[i] = twiceP.add(preComp[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the Window NAF of the desired width
|
||||
byte[] wnaf = windowNaf(width, k);
|
||||
int l = wnaf.length;
|
||||
|
||||
// Apply the Window NAF to p using the precomputed ECPoint values.
|
||||
ECPoint q = p.getCurve().getInfinity();
|
||||
for (int i = l - 1; i >= 0; i--)
|
||||
{
|
||||
q = q.twice();
|
||||
|
||||
if (wnaf[i] != 0)
|
||||
{
|
||||
if (wnaf[i] > 0)
|
||||
{
|
||||
q = q.add(preComp[(wnaf[i] - 1)/2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// wnaf[i] < 0
|
||||
q = q.subtract(preComp[(-wnaf[i] - 1)/2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set PreCompInfo in ECPoint, such that it is available for next
|
||||
// multiplication.
|
||||
wnafPreCompInfo.setPreComp(preComp);
|
||||
wnafPreCompInfo.setTwiceP(twiceP);
|
||||
p.setPreCompInfo(wnafPreCompInfo);
|
||||
return q;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
/**
|
||||
* Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
|
||||
* algorithm.
|
||||
*/
|
||||
class WNafPreCompInfo implements PreCompInfo
|
||||
{
|
||||
/**
|
||||
* Array holding the precomputed <code>ECPoint</code>s used for the Window
|
||||
* NAF multiplication in <code>
|
||||
* {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
|
||||
* WNafMultiplier.multiply()}</code>.
|
||||
*/
|
||||
private ECPoint[] preComp = null;
|
||||
|
||||
/**
|
||||
* Holds an <code>ECPoint</code> representing twice(this). Used for the
|
||||
* Window NAF multiplication in <code>
|
||||
* {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
|
||||
* WNafMultiplier.multiply()}</code>.
|
||||
*/
|
||||
private ECPoint twiceP = null;
|
||||
|
||||
protected ECPoint[] getPreComp()
|
||||
{
|
||||
return preComp;
|
||||
}
|
||||
|
||||
protected void setPreComp(ECPoint[] preComp)
|
||||
{
|
||||
this.preComp = preComp;
|
||||
}
|
||||
|
||||
protected ECPoint getTwiceP()
|
||||
{
|
||||
return twiceP;
|
||||
}
|
||||
|
||||
protected void setTwiceP(ECPoint twiceThis)
|
||||
{
|
||||
this.twiceP = twiceThis;
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Class implementing the WTNAF (Window
|
||||
* <code>τ</code>-adic Non-Adjacent Form) algorithm.
|
||||
*/
|
||||
class WTauNafMultiplier implements ECMultiplier
|
||||
{
|
||||
/**
|
||||
* Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
|
||||
* by <code>k</code> using the reduced <code>τ</code>-adic NAF (RTNAF)
|
||||
* method.
|
||||
* @param p The ECPoint.F2m to multiply.
|
||||
* @param k The integer by which to multiply <code>k</code>.
|
||||
* @return <code>p</code> multiplied by <code>k</code>.
|
||||
*/
|
||||
public ECPoint multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo)
|
||||
{
|
||||
if (!(point instanceof ECPoint.F2m))
|
||||
{
|
||||
throw new IllegalArgumentException("Only ECPoint.F2m can be " +
|
||||
"used in WTauNafMultiplier");
|
||||
}
|
||||
|
||||
ECPoint.F2m p = (ECPoint.F2m)point;
|
||||
|
||||
ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
|
||||
int m = curve.getM();
|
||||
byte a = curve.getA().toBigInteger().byteValue();
|
||||
byte mu = curve.getMu();
|
||||
BigInteger[] s = curve.getSi();
|
||||
|
||||
ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);
|
||||
|
||||
return multiplyWTnaf(p, rho, preCompInfo, a, mu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
|
||||
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code> using
|
||||
* the <code>τ</code>-adic NAF (TNAF) method.
|
||||
* @param p The ECPoint.F2m to multiply.
|
||||
* @param lambda The element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code> of which to compute the
|
||||
* <code>[τ]</code>-adic NAF.
|
||||
* @return <code>p</code> multiplied by <code>λ</code>.
|
||||
*/
|
||||
private ECPoint.F2m multiplyWTnaf(ECPoint.F2m p, ZTauElement lambda,
|
||||
PreCompInfo preCompInfo, byte a, byte mu)
|
||||
{
|
||||
ZTauElement[] alpha;
|
||||
if (a == 0)
|
||||
{
|
||||
alpha = Tnaf.alpha0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// a == 1
|
||||
alpha = Tnaf.alpha1;
|
||||
}
|
||||
|
||||
BigInteger tw = Tnaf.getTw(mu, Tnaf.WIDTH);
|
||||
|
||||
byte[]u = Tnaf.tauAdicWNaf(mu, lambda, Tnaf.WIDTH,
|
||||
BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha);
|
||||
|
||||
return multiplyFromWTnaf(p, u, preCompInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
|
||||
* by an element <code>λ</code> of <code><b>Z</b>[τ]</code>
|
||||
* using the window <code>τ</code>-adic NAF (TNAF) method, given the
|
||||
* WTNAF of <code>λ</code>.
|
||||
* @param p The ECPoint.F2m to multiply.
|
||||
* @param u The the WTNAF of <code>λ</code>..
|
||||
* @return <code>λ * p</code>
|
||||
*/
|
||||
private static ECPoint.F2m multiplyFromWTnaf(ECPoint.F2m p, byte[] u,
|
||||
PreCompInfo preCompInfo)
|
||||
{
|
||||
ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
|
||||
byte a = curve.getA().toBigInteger().byteValue();
|
||||
|
||||
ECPoint.F2m[] pu;
|
||||
if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo))
|
||||
{
|
||||
pu = Tnaf.getPreComp(p, a);
|
||||
p.setPreCompInfo(new WTauNafPreCompInfo(pu));
|
||||
}
|
||||
else
|
||||
{
|
||||
pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp();
|
||||
}
|
||||
|
||||
// q = infinity
|
||||
ECPoint.F2m q = (ECPoint.F2m) p.getCurve().getInfinity();
|
||||
for (int i = u.length - 1; i >= 0; i--)
|
||||
{
|
||||
q = Tnaf.tau(q);
|
||||
if (u[i] != 0)
|
||||
{
|
||||
if (u[i] > 0)
|
||||
{
|
||||
q = q.addSimple(pu[u[i]]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// u[i] < 0
|
||||
q = q.subtractSimple(pu[-u[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
/**
|
||||
* Class holding precomputation data for the WTNAF (Window
|
||||
* <code>τ</code>-adic Non-Adjacent Form) algorithm.
|
||||
*/
|
||||
class WTauNafPreCompInfo implements PreCompInfo
|
||||
{
|
||||
/**
|
||||
* Array holding the precomputed <code>ECPoint.F2m</code>s used for the
|
||||
* WTNAF multiplication in <code>
|
||||
* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
|
||||
* WTauNafMultiplier.multiply()}</code>.
|
||||
*/
|
||||
private ECPoint.F2m[] preComp = null;
|
||||
|
||||
/**
|
||||
* Constructor for <code>WTauNafPreCompInfo</code>
|
||||
* @param preComp Array holding the precomputed <code>ECPoint.F2m</code>s
|
||||
* used for the WTNAF multiplication in <code>
|
||||
* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
|
||||
* WTauNafMultiplier.multiply()}</code>.
|
||||
*/
|
||||
WTauNafPreCompInfo(ECPoint.F2m[] preComp)
|
||||
{
|
||||
this.preComp = preComp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the array holding the precomputed <code>ECPoint.F2m</code>s
|
||||
* used for the WTNAF multiplication in <code>
|
||||
* {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
|
||||
* WTauNafMultiplier.multiply()}</code>.
|
||||
*/
|
||||
protected ECPoint.F2m[] getPreComp()
|
||||
{
|
||||
return preComp;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package org.bouncycastle.math.ec;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* Class representing an element of <code><b>Z</b>[τ]</code>. Let
|
||||
* <code>λ</code> be an element of <code><b>Z</b>[τ]</code>. Then
|
||||
* <code>λ</code> is given as <code>λ = u + vτ</code>. The
|
||||
* components <code>u</code> and <code>v</code> may be used directly, there
|
||||
* are no accessor methods.
|
||||
* Immutable class.
|
||||
*/
|
||||
class ZTauElement
|
||||
{
|
||||
/**
|
||||
* The "real" part of <code>λ</code>.
|
||||
*/
|
||||
public final BigInteger u;
|
||||
|
||||
/**
|
||||
* The "<code>τ</code>-adic" part of <code>λ</code>.
|
||||
*/
|
||||
public final BigInteger v;
|
||||
|
||||
/**
|
||||
* Constructor for an element <code>λ</code> of
|
||||
* <code><b>Z</b>[τ]</code>.
|
||||
* @param u The "real" part of <code>λ</code>.
|
||||
* @param v The "<code>τ</code>-adic" part of
|
||||
* <code>λ</code>.
|
||||
*/
|
||||
public ZTauElement(BigInteger u, BigInteger v)
|
||||
{
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<html>
|
||||
<body bgcolor="#ffffff">
|
||||
Math support for Elliptic Curve.
|
||||
</body>
|
||||
</html>
|
|
@ -1,177 +0,0 @@
|
|||
package org.bouncycastle.util;
|
||||
|
||||
/**
|
||||
* General array utilities.
|
||||
*/
|
||||
public final class Arrays
|
||||
{
|
||||
private Arrays()
|
||||
{
|
||||
// static class, hide constructor
|
||||
}
|
||||
|
||||
public static boolean areEqual(
|
||||
boolean[] a,
|
||||
boolean[] b)
|
||||
{
|
||||
if (a == b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == null || b == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.length != b.length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i != a.length; i++)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean areEqual(
|
||||
byte[] a,
|
||||
byte[] b)
|
||||
{
|
||||
if (a == b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == null || b == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.length != b.length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i != a.length; i++)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean areEqual(
|
||||
int[] a,
|
||||
int[] b)
|
||||
{
|
||||
if (a == b)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a == null || b == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.length != b.length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i != a.length; i++)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void fill(
|
||||
byte[] array,
|
||||
byte value)
|
||||
{
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fill(
|
||||
long[] array,
|
||||
long value)
|
||||
{
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void fill(
|
||||
short[] array,
|
||||
short value)
|
||||
{
|
||||
for (int i = 0; i < array.length; i++)
|
||||
{
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static int hashCode(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = data.length;
|
||||
int hc = i + 1;
|
||||
|
||||
while (--i >= 0)
|
||||
{
|
||||
hc *= 257;
|
||||
hc ^= data[i];
|
||||
}
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
public static byte[] clone(byte[] data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] copy = new byte[data.length];
|
||||
|
||||
System.arraycopy(data, 0, copy, 0, data.length);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static int[] clone(int[] data)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int[] copy = new int[data.length];
|
||||
|
||||
System.arraycopy(data, 0, copy, 0, data.length);
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
package org.bouncycastle.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Vector;
|
||||
|
||||
public final class Strings
|
||||
{
|
||||
public static String fromUTF8ByteArray(byte[] bytes)
|
||||
{
|
||||
int i = 0;
|
||||
int length = 0;
|
||||
|
||||
while (i < bytes.length)
|
||||
{
|
||||
length++;
|
||||
if ((bytes[i] & 0xf0) == 0xf0)
|
||||
{
|
||||
// surrogate pair
|
||||
length++;
|
||||
i += 4;
|
||||
}
|
||||
else if ((bytes[i] & 0xe0) == 0xe0)
|
||||
{
|
||||
i += 3;
|
||||
}
|
||||
else if ((bytes[i] & 0xc0) == 0xc0)
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
char[] cs = new char[length];
|
||||
|
||||
i = 0;
|
||||
length = 0;
|
||||
|
||||
while (i < bytes.length)
|
||||
{
|
||||
char ch;
|
||||
|
||||
if ((bytes[i] & 0xf0) == 0xf0)
|
||||
{
|
||||
int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i+1] & 0x3F) << 12) | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F);
|
||||
int U = codePoint - 0x10000;
|
||||
char W1 = (char)(0xD800 | (U >> 10));
|
||||
char W2 = (char)(0xDC00 | (U & 0x3FF));
|
||||
cs[length++] = W1;
|
||||
ch = W2;
|
||||
i += 4;
|
||||
}
|
||||
else if ((bytes[i] & 0xe0) == 0xe0)
|
||||
{
|
||||
ch = (char)(((bytes[i] & 0x0f) << 12)
|
||||
| ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
|
||||
i += 3;
|
||||
}
|
||||
else if ((bytes[i] & 0xd0) == 0xd0)
|
||||
{
|
||||
ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
|
||||
i += 2;
|
||||
}
|
||||
else if ((bytes[i] & 0xc0) == 0xc0)
|
||||
{
|
||||
ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = (char)(bytes[i] & 0xff);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
cs[length++] = ch;
|
||||
}
|
||||
|
||||
return new String(cs);
|
||||
}
|
||||
|
||||
public static byte[] toUTF8ByteArray(String string)
|
||||
{
|
||||
return toUTF8ByteArray(string.toCharArray());
|
||||
}
|
||||
|
||||
public static byte[] toUTF8ByteArray(char[] string)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
char[] c = string;
|
||||
int i = 0;
|
||||
|
||||
while (i < c.length)
|
||||
{
|
||||
char ch = c[i];
|
||||
|
||||
if (ch < 0x0080)
|
||||
{
|
||||
bOut.write(ch);
|
||||
}
|
||||
else if (ch < 0x0800)
|
||||
{
|
||||
bOut.write(0xc0 | (ch >> 6));
|
||||
bOut.write(0x80 | (ch & 0x3f));
|
||||
}
|
||||
// surrogate pair
|
||||
else if (ch >= 0xD800 && ch <= 0xDFFF)
|
||||
{
|
||||
// in error - can only happen, if the Java String class has a
|
||||
// bug.
|
||||
if (i + 1 >= c.length)
|
||||
{
|
||||
throw new IllegalStateException("invalid UTF-16 codepoint");
|
||||
}
|
||||
char W1 = ch;
|
||||
ch = c[++i];
|
||||
char W2 = ch;
|
||||
// in error - can only happen, if the Java String class has a
|
||||
// bug.
|
||||
if (W1 > 0xDBFF)
|
||||
{
|
||||
throw new IllegalStateException("invalid UTF-16 codepoint");
|
||||
}
|
||||
int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
|
||||
bOut.write(0xf0 | (codePoint >> 18));
|
||||
bOut.write(0x80 | ((codePoint >> 12) & 0x3F));
|
||||
bOut.write(0x80 | ((codePoint >> 6) & 0x3F));
|
||||
bOut.write(0x80 | (codePoint & 0x3F));
|
||||
}
|
||||
else
|
||||
{
|
||||
bOut.write(0xe0 | (ch >> 12));
|
||||
bOut.write(0x80 | ((ch >> 6) & 0x3F));
|
||||
bOut.write(0x80 | (ch & 0x3F));
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* A locale independent version of toUpperCase.
|
||||
*
|
||||
* @param string input to be converted
|
||||
* @return a US Ascii uppercase version
|
||||
*/
|
||||
public static String toUpperCase(String string)
|
||||
{
|
||||
boolean changed = false;
|
||||
char[] chars = string.toCharArray();
|
||||
|
||||
for (int i = 0; i != chars.length; i++)
|
||||
{
|
||||
char ch = chars[i];
|
||||
if ('a' <= ch && 'z' >= ch)
|
||||
{
|
||||
changed = true;
|
||||
chars[i] = (char)(ch - 'a' + 'A');
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A locale independent version of toLowerCase.
|
||||
*
|
||||
* @param string input to be converted
|
||||
* @return a US ASCII lowercase version
|
||||
*/
|
||||
public static String toLowerCase(String string)
|
||||
{
|
||||
boolean changed = false;
|
||||
char[] chars = string.toCharArray();
|
||||
|
||||
for (int i = 0; i != chars.length; i++)
|
||||
{
|
||||
char ch = chars[i];
|
||||
if ('A' <= ch && 'Z' >= ch)
|
||||
{
|
||||
changed = true;
|
||||
chars[i] = (char)(ch - 'A' + 'a');
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(String string)
|
||||
{
|
||||
byte[] bytes = new byte[string.length()];
|
||||
|
||||
for (int i = 0; i != bytes.length; i++)
|
||||
{
|
||||
char ch = string.charAt(i);
|
||||
|
||||
bytes[i] = (byte)ch;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static String[] split(String input, char delimiter)
|
||||
{
|
||||
Vector v = new Vector();
|
||||
boolean moreTokens = true;
|
||||
String subString;
|
||||
|
||||
while (moreTokens)
|
||||
{
|
||||
int tokenLocation = input.indexOf(delimiter);
|
||||
if (tokenLocation > 0)
|
||||
{
|
||||
subString = input.substring(0, tokenLocation);
|
||||
v.addElement(subString);
|
||||
input = input.substring(tokenLocation + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
moreTokens = false;
|
||||
v.addElement(input);
|
||||
}
|
||||
}
|
||||
|
||||
String[] res = new String[v.size()];
|
||||
|
||||
for (int i = 0; i != res.length; i++)
|
||||
{
|
||||
res[i] = (String)v.elementAt(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package org.bouncycastle.util.encoders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Encode and decode byte arrays (typically from binary to 7-bit ASCII
|
||||
* encodings).
|
||||
*/
|
||||
public interface Encoder
|
||||
{
|
||||
int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
|
||||
|
||||
int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
|
||||
|
||||
int decode(String data, OutputStream out) throws IOException;
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
package org.bouncycastle.util.encoders;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class Hex
|
||||
{
|
||||
private static final Encoder encoder = new HexEncoder();
|
||||
|
||||
/**
|
||||
* encode the input data producing a Hex encoded byte array.
|
||||
*
|
||||
* @return a byte array containing the Hex encoded data.
|
||||
*/
|
||||
public static byte[] encode(
|
||||
byte[] data)
|
||||
{
|
||||
return encode(data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* encode the input data producing a Hex encoded byte array.
|
||||
*
|
||||
* @return a byte array containing the Hex encoded data.
|
||||
*/
|
||||
public static byte[] encode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
encoder.encode(data, off, length, bOut);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("exception encoding Hex string: " + e);
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex encode the byte data writing it to the given output stream.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public static int encode(
|
||||
byte[] data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
return encoder.encode(data, 0, data.length, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex encode the byte data writing it to the given output stream.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public static int encode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
return encoder.encode(data, off, length, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded input data. It is assumed the input data is valid.
|
||||
*
|
||||
* @return a byte array representing the decoded data.
|
||||
*/
|
||||
public static byte[] decode(
|
||||
byte[] data)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
encoder.decode(data, 0, data.length, bOut);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("exception decoding Hex string: " + e);
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded String data - whitespace will be ignored.
|
||||
*
|
||||
* @return a byte array representing the decoded data.
|
||||
*/
|
||||
public static byte[] decode(
|
||||
String data)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
encoder.decode(data, bOut);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException("exception decoding Hex string: " + e);
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded String data writing it to the given output stream,
|
||||
* whitespace characters will be ignored.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public static int decode(
|
||||
String data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
return encoder.decode(data, out);
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
package org.bouncycastle.util.encoders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class HexEncoder
|
||||
implements Encoder
|
||||
{
|
||||
protected final byte[] encodingTable =
|
||||
{
|
||||
(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7',
|
||||
(byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'
|
||||
};
|
||||
|
||||
/*
|
||||
* set up the decoding table.
|
||||
*/
|
||||
protected final byte[] decodingTable = new byte[128];
|
||||
|
||||
protected void initialiseDecodingTable()
|
||||
{
|
||||
for (int i = 0; i < encodingTable.length; i++)
|
||||
{
|
||||
decodingTable[encodingTable[i]] = (byte)i;
|
||||
}
|
||||
|
||||
decodingTable['A'] = decodingTable['a'];
|
||||
decodingTable['B'] = decodingTable['b'];
|
||||
decodingTable['C'] = decodingTable['c'];
|
||||
decodingTable['D'] = decodingTable['d'];
|
||||
decodingTable['E'] = decodingTable['e'];
|
||||
decodingTable['F'] = decodingTable['f'];
|
||||
}
|
||||
|
||||
public HexEncoder()
|
||||
{
|
||||
initialiseDecodingTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* encode the input data producing a Hex output stream.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public int encode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
for (int i = off; i < (off + length); i++)
|
||||
{
|
||||
int v = data[i] & 0xff;
|
||||
|
||||
out.write(encodingTable[(v >>> 4)]);
|
||||
out.write(encodingTable[v & 0xf]);
|
||||
}
|
||||
|
||||
return length * 2;
|
||||
}
|
||||
|
||||
private boolean ignore(
|
||||
char c)
|
||||
{
|
||||
return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded byte data writing it to the given output stream,
|
||||
* whitespace characters will be ignored.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public int decode(
|
||||
byte[] data,
|
||||
int off,
|
||||
int length,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
byte b1, b2;
|
||||
int outLen = 0;
|
||||
|
||||
int end = off + length;
|
||||
|
||||
while (end > off)
|
||||
{
|
||||
if (!ignore((char)data[end - 1]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
end--;
|
||||
}
|
||||
|
||||
int i = off;
|
||||
while (i < end)
|
||||
{
|
||||
while (i < end && ignore((char)data[i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b1 = decodingTable[data[i++]];
|
||||
|
||||
while (i < end && ignore((char)data[i]))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b2 = decodingTable[data[i++]];
|
||||
|
||||
out.write((b1 << 4) | b2);
|
||||
|
||||
outLen++;
|
||||
}
|
||||
|
||||
return outLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode the Hex encoded String data writing it to the given output stream,
|
||||
* whitespace characters will be ignored.
|
||||
*
|
||||
* @return the number of bytes produced.
|
||||
*/
|
||||
public int decode(
|
||||
String data,
|
||||
OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
byte b1, b2;
|
||||
int length = 0;
|
||||
|
||||
int end = data.length();
|
||||
|
||||
while (end > 0)
|
||||
{
|
||||
if (!ignore(data.charAt(end - 1)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
end--;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while (i < end)
|
||||
{
|
||||
while (i < end && ignore(data.charAt(i)))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b1 = decodingTable[data.charAt(i++)];
|
||||
|
||||
while (i < end && ignore(data.charAt(i)))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
b2 = decodingTable[data.charAt(i++)];
|
||||
|
||||
out.write((b1 << 4) | b2);
|
||||
|
||||
length++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package org.bouncycastle.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class StreamOverflowException
|
||||
extends IOException
|
||||
{
|
||||
public StreamOverflowException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package org.bouncycastle.util.io;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public final class Streams
|
||||
{
|
||||
private static int BUFFER_SIZE = 512;
|
||||
|
||||
public static void drain(InputStream inStr)
|
||||
throws IOException
|
||||
{
|
||||
byte[] bs = new byte[BUFFER_SIZE];
|
||||
while (inStr.read(bs, 0, bs.length) >= 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readAll(InputStream inStr)
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
pipeAll(inStr, buf);
|
||||
return buf.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] readAllLimited(InputStream inStr, int limit)
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||
pipeAllLimited(inStr, limit, buf);
|
||||
return buf.toByteArray();
|
||||
}
|
||||
|
||||
public static int readFully(InputStream inStr, byte[] buf)
|
||||
throws IOException
|
||||
{
|
||||
return readFully(inStr, buf, 0, buf.length);
|
||||
}
|
||||
|
||||
public static int readFully(InputStream inStr, byte[] buf, int off, int len)
|
||||
throws IOException
|
||||
{
|
||||
int totalRead = 0;
|
||||
while (totalRead < len)
|
||||
{
|
||||
int numRead = inStr.read(buf, off + totalRead, len - totalRead);
|
||||
if (numRead < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
totalRead += numRead;
|
||||
}
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
public static void pipeAll(InputStream inStr, OutputStream outStr)
|
||||
throws IOException
|
||||
{
|
||||
byte[] bs = new byte[BUFFER_SIZE];
|
||||
int numRead;
|
||||
while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
|
||||
{
|
||||
outStr.write(bs, 0, numRead);
|
||||
}
|
||||
}
|
||||
|
||||
public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr)
|
||||
throws IOException
|
||||
{
|
||||
long total = 0;
|
||||
byte[] bs = new byte[BUFFER_SIZE];
|
||||
int numRead;
|
||||
while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
|
||||
{
|
||||
total += numRead;
|
||||
if (total > limit)
|
||||
throw new StreamOverflowException("Data Overflow");
|
||||
outStr.write(bs, 0, numRead);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ASN1ApplicationSpecificParser
|
||||
extends DEREncodable
|
||||
{
|
||||
DEREncodable readObject()
|
||||
throws IOException;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
/**
|
||||
* Marker interface for CHOICE objects - if you implement this in a role your
|
||||
* own object any attempt to tag the object implicitly will convert the tag to
|
||||
* an explicit one as the encoding rules require.
|
||||
* <p>
|
||||
* If you use this interface your class should also implement the getInstance
|
||||
* pattern which takes a tag object and the tagging mode used.
|
||||
*/
|
||||
public interface ASN1Choice
|
||||
{
|
||||
// marker interface
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Base class for objects which can be written directly to ASN.1 output streams.
|
||||
*/
|
||||
public abstract class ASN1Encodable
|
||||
implements DEREncodable
|
||||
{
|
||||
public static final String DER = "DER";
|
||||
public static final String BER = "BER";
|
||||
|
||||
/**
|
||||
* Return the default BER or DER encoding for this object.
|
||||
*
|
||||
* @return BER/DER byte encoded object.
|
||||
* @throws IOException on encoding error.
|
||||
*/
|
||||
public byte[] getEncoded()
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
||||
|
||||
aOut.writeObject(this);
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return either the default for "BER" or a DER encoding if "DER" is specified.
|
||||
*
|
||||
* @param encoding name of encoding to use.
|
||||
* @return byte encoded object.
|
||||
* @throws IOException on encoding error.
|
||||
*/
|
||||
public byte[] getEncoded(
|
||||
String encoding)
|
||||
throws IOException
|
||||
{
|
||||
if (encoding.equals(DER))
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
DEROutputStream dOut = new DEROutputStream(bOut);
|
||||
|
||||
dOut.writeObject(this);
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
return this.getEncoded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DER encoding of the object, null if the DER encoding can not be made.
|
||||
*
|
||||
* @return a DER byte array, null otherwise.
|
||||
*/
|
||||
public byte[] getDEREncoded()
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.getEncoded(DER);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return this.toASN1Object().hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(
|
||||
Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof DEREncodable))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DEREncodable other = (DEREncodable)o;
|
||||
|
||||
return this.toASN1Object().equals(other.getDERObject());
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
return this.toASN1Object();
|
||||
}
|
||||
|
||||
public abstract DERObject toASN1Object();
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
/**
|
||||
* the parent class for this will eventually disappear. Use this one!
|
||||
*/
|
||||
public class ASN1EncodableVector
|
||||
extends DEREncodableVector
|
||||
{
|
||||
// migrating from DEREncodeableVector
|
||||
public ASN1EncodableVector()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
|
||||
/**
|
||||
* a general purpose ASN.1 decoder - note: this class differs from the
|
||||
* others in that it returns null after it has read the last object in
|
||||
* the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
|
||||
* returned.
|
||||
*/
|
||||
public class ASN1InputStream
|
||||
extends FilterInputStream
|
||||
implements DERTags
|
||||
{
|
||||
private final int limit;
|
||||
private final boolean lazyEvaluate;
|
||||
|
||||
public ASN1InputStream(
|
||||
InputStream is)
|
||||
{
|
||||
this(is, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ASN1InputStream based on the input byte array. The length of DER objects in
|
||||
* the stream is automatically limited to the length of the input array.
|
||||
*
|
||||
* @param input array containing ASN.1 encoded data.
|
||||
*/
|
||||
public ASN1InputStream(
|
||||
byte[] input)
|
||||
{
|
||||
this(new ByteArrayInputStream(input), input.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ASN1InputStream based on the input byte array. The length of DER objects in
|
||||
* the stream is automatically limited to the length of the input array.
|
||||
*
|
||||
* @param input array containing ASN.1 encoded data.
|
||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed.
|
||||
*/
|
||||
public ASN1InputStream(
|
||||
byte[] input,
|
||||
boolean lazyEvaluate)
|
||||
{
|
||||
this(new ByteArrayInputStream(input), input.length, lazyEvaluate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ASN1InputStream where no DER object will be longer than limit.
|
||||
*
|
||||
* @param input stream containing ASN.1 encoded data.
|
||||
* @param limit maximum size of a DER encoded object.
|
||||
*/
|
||||
public ASN1InputStream(
|
||||
InputStream input,
|
||||
int limit)
|
||||
{
|
||||
this(input, limit, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ASN1InputStream where no DER object will be longer than limit, and constructed
|
||||
* objects such as sequences will be parsed lazily.
|
||||
*
|
||||
* @param input stream containing ASN.1 encoded data.
|
||||
* @param limit maximum size of a DER encoded object.
|
||||
* @param lazyEvaluate true if parsing inside constructed objects can be delayed.
|
||||
*/
|
||||
public ASN1InputStream(
|
||||
InputStream input,
|
||||
int limit,
|
||||
boolean lazyEvaluate)
|
||||
{
|
||||
super(input);
|
||||
this.limit = limit;
|
||||
this.lazyEvaluate = lazyEvaluate;
|
||||
}
|
||||
|
||||
protected int readLength()
|
||||
throws IOException
|
||||
{
|
||||
return readLength(this, limit);
|
||||
}
|
||||
|
||||
protected void readFully(
|
||||
byte[] bytes)
|
||||
throws IOException
|
||||
{
|
||||
if (Streams.readFully(this, bytes) != bytes.length)
|
||||
{
|
||||
throw new EOFException("EOF encountered in middle of object");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build an object given its tag and the number of bytes to construct it from.
|
||||
*/
|
||||
protected DERObject buildObject(
|
||||
int tag,
|
||||
int tagNo,
|
||||
int length)
|
||||
throws IOException
|
||||
{
|
||||
boolean isConstructed = (tag & CONSTRUCTED) != 0;
|
||||
|
||||
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);
|
||||
|
||||
if ((tag & APPLICATION) != 0)
|
||||
{
|
||||
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
|
||||
}
|
||||
|
||||
if ((tag & TAGGED) != 0)
|
||||
{
|
||||
return new BERTaggedObjectParser(tag, tagNo, defIn).getDERObject();
|
||||
}
|
||||
|
||||
if (isConstructed)
|
||||
{
|
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo)
|
||||
{
|
||||
case OCTET_STRING:
|
||||
//
|
||||
// yes, people actually do this...
|
||||
//
|
||||
return new BERConstructedOctetString(buildDEREncodableVector(defIn).v);
|
||||
case SEQUENCE:
|
||||
if (lazyEvaluate)
|
||||
{
|
||||
return new LazyDERSequence(defIn.toByteArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
return DERFactory.createSequence(buildDEREncodableVector(defIn));
|
||||
}
|
||||
case SET:
|
||||
return DERFactory.createSet(buildDEREncodableVector(defIn), false);
|
||||
default:
|
||||
return new DERUnknownTag(true, tagNo, defIn.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
return createPrimitiveDERObject(tagNo, defIn.toByteArray());
|
||||
}
|
||||
|
||||
ASN1EncodableVector buildEncodableVector()
|
||||
throws IOException
|
||||
{
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
DERObject o;
|
||||
|
||||
while ((o = readObject()) != null)
|
||||
{
|
||||
v.add(o);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
ASN1EncodableVector buildDEREncodableVector(
|
||||
DefiniteLengthInputStream dIn) throws IOException
|
||||
{
|
||||
return new ASN1InputStream(dIn).buildEncodableVector();
|
||||
}
|
||||
|
||||
public DERObject readObject()
|
||||
throws IOException
|
||||
{
|
||||
int tag = read();
|
||||
if (tag <= 0)
|
||||
{
|
||||
if (tag == 0)
|
||||
{
|
||||
throw new IOException("unexpected end-of-contents marker");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// calculate tag number
|
||||
//
|
||||
int tagNo = readTagNumber(this, tag);
|
||||
|
||||
boolean isConstructed = (tag & CONSTRUCTED) != 0;
|
||||
|
||||
//
|
||||
// calculate length
|
||||
//
|
||||
int length = readLength();
|
||||
|
||||
if (length < 0) // indefinite length method
|
||||
{
|
||||
if (!isConstructed)
|
||||
{
|
||||
throw new IOException("indefinite length primitive encoding encountered");
|
||||
}
|
||||
|
||||
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this);
|
||||
|
||||
if ((tag & APPLICATION) != 0)
|
||||
{
|
||||
ASN1StreamParser sp = new ASN1StreamParser(indIn);
|
||||
|
||||
return new BERApplicationSpecificParser(tagNo, sp).getDERObject();
|
||||
}
|
||||
if ((tag & TAGGED) != 0)
|
||||
{
|
||||
return new BERTaggedObjectParser(tag, tagNo, indIn).getDERObject();
|
||||
}
|
||||
|
||||
ASN1StreamParser sp = new ASN1StreamParser(indIn);
|
||||
|
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo)
|
||||
{
|
||||
case OCTET_STRING:
|
||||
return new BEROctetStringParser(sp).getDERObject();
|
||||
case SEQUENCE:
|
||||
return new BERSequenceParser(sp).getDERObject();
|
||||
case SET:
|
||||
return new BERSetParser(sp).getDERObject();
|
||||
default:
|
||||
throw new IOException("unknown BER object encountered");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return buildObject(tag, tagNo, length);
|
||||
}
|
||||
}
|
||||
|
||||
static int readTagNumber(InputStream s, int tag)
|
||||
throws IOException
|
||||
{
|
||||
int tagNo = tag & 0x1f;
|
||||
|
||||
//
|
||||
// with tagged object tag number is bottom 5 bits, or stored at the start of the content
|
||||
//
|
||||
if (tagNo == 0x1f)
|
||||
{
|
||||
tagNo = 0;
|
||||
|
||||
int b = s.read();
|
||||
|
||||
// X.690-0207 8.1.2.4.2
|
||||
// "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
|
||||
if ((b & 0x7f) == 0) // Note: -1 will pass
|
||||
{
|
||||
throw new IOException("corrupted stream - invalid high tag number found");
|
||||
}
|
||||
|
||||
while ((b >= 0) && ((b & 0x80) != 0))
|
||||
{
|
||||
tagNo |= (b & 0x7f);
|
||||
tagNo <<= 7;
|
||||
b = s.read();
|
||||
}
|
||||
|
||||
if (b < 0)
|
||||
{
|
||||
throw new EOFException("EOF found inside tag value.");
|
||||
}
|
||||
|
||||
tagNo |= (b & 0x7f);
|
||||
}
|
||||
|
||||
return tagNo;
|
||||
}
|
||||
|
||||
static int readLength(InputStream s, int limit)
|
||||
throws IOException
|
||||
{
|
||||
int length = s.read();
|
||||
if (length < 0)
|
||||
{
|
||||
throw new EOFException("EOF found when length expected");
|
||||
}
|
||||
|
||||
if (length == 0x80)
|
||||
{
|
||||
return -1; // indefinite-length encoding
|
||||
}
|
||||
|
||||
if (length > 127)
|
||||
{
|
||||
int size = length & 0x7f;
|
||||
|
||||
if (size > 4)
|
||||
{
|
||||
throw new IOException("DER length more than 4 bytes");
|
||||
}
|
||||
|
||||
length = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
int next = s.read();
|
||||
|
||||
if (next < 0)
|
||||
{
|
||||
throw new EOFException("EOF found reading length");
|
||||
}
|
||||
|
||||
length = (length << 8) + next;
|
||||
}
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
throw new IOException("corrupted stream - negative length found");
|
||||
}
|
||||
|
||||
if (length >= limit) // after all we must have read at least 1 byte
|
||||
{
|
||||
throw new IOException("corrupted stream - out of bounds length found");
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static DERObject createPrimitiveDERObject(
|
||||
int tagNo,
|
||||
byte[] bytes)
|
||||
{
|
||||
switch (tagNo)
|
||||
{
|
||||
case BIT_STRING:
|
||||
{
|
||||
int padBits = bytes[0];
|
||||
byte[] data = new byte[bytes.length - 1];
|
||||
System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
|
||||
return new DERBitString(data, padBits);
|
||||
}
|
||||
case BMP_STRING:
|
||||
return new DERBMPString(bytes);
|
||||
case BOOLEAN:
|
||||
return new DERBoolean(bytes);
|
||||
case ENUMERATED:
|
||||
return new DEREnumerated(bytes);
|
||||
case GENERALIZED_TIME:
|
||||
return new DERGeneralizedTime(bytes);
|
||||
case GENERAL_STRING:
|
||||
return new DERGeneralString(bytes);
|
||||
case IA5_STRING:
|
||||
return new DERIA5String(bytes);
|
||||
case INTEGER:
|
||||
return new DERInteger(bytes);
|
||||
case NULL:
|
||||
return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?)
|
||||
case NUMERIC_STRING:
|
||||
return new DERNumericString(bytes);
|
||||
case OBJECT_IDENTIFIER:
|
||||
return new DERObjectIdentifier(bytes);
|
||||
case OCTET_STRING:
|
||||
return new DEROctetString(bytes);
|
||||
case PRINTABLE_STRING:
|
||||
return new DERPrintableString(bytes);
|
||||
case T61_STRING:
|
||||
return new DERT61String(bytes);
|
||||
case UNIVERSAL_STRING:
|
||||
return new DERUniversalString(bytes);
|
||||
case UTC_TIME:
|
||||
return new DERUTCTime(bytes);
|
||||
case UTF8_STRING:
|
||||
return new DERUTF8String(bytes);
|
||||
case VISIBLE_STRING:
|
||||
return new DERVisibleString(bytes);
|
||||
default:
|
||||
return new DERUnknownTag(false, tagNo, bytes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A NULL object.
|
||||
*/
|
||||
public abstract class ASN1Null
|
||||
extends ASN1Object
|
||||
{
|
||||
public ASN1Null()
|
||||
{
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
DERObject o)
|
||||
{
|
||||
if (!(o instanceof ASN1Null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract void encode(DEROutputStream out)
|
||||
throws IOException;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "NULL";
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class ASN1Object
|
||||
extends DERObject
|
||||
{
|
||||
/**
|
||||
* Create a base ASN.1 object from a byte stream.
|
||||
*
|
||||
* @param data the byte stream to parse.
|
||||
* @return the base ASN.1 object represented by the byte stream.
|
||||
* @exception IOException if there is a problem parsing the data.
|
||||
*/
|
||||
public static ASN1Object fromByteArray(byte[] data)
|
||||
throws IOException
|
||||
{
|
||||
ASN1InputStream aIn = new ASN1InputStream(data);
|
||||
|
||||
return (ASN1Object)aIn.readObject();
|
||||
}
|
||||
|
||||
public final boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return (o instanceof DEREncodable) && asn1Equals(((DEREncodable)o).getDERObject());
|
||||
}
|
||||
|
||||
public abstract int hashCode();
|
||||
|
||||
abstract void encode(DEROutputStream out) throws IOException;
|
||||
|
||||
abstract boolean asn1Equals(DERObject o);
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @deprecated will be removed
|
||||
*/
|
||||
public class ASN1ObjectParser
|
||||
{
|
||||
ASN1StreamParser _aIn;
|
||||
|
||||
protected ASN1ObjectParser(
|
||||
int baseTag,
|
||||
int tagNumber,
|
||||
InputStream contentStream)
|
||||
{
|
||||
_aIn = new ASN1StreamParser(contentStream);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
public abstract class ASN1OctetString
|
||||
extends ASN1Object
|
||||
implements ASN1OctetStringParser
|
||||
{
|
||||
byte[] string;
|
||||
|
||||
/**
|
||||
* return an Octet String from a tagged object.
|
||||
*
|
||||
* @param obj the tagged object holding the object we want.
|
||||
* @param explicit true if the object is meant to be explicitly
|
||||
* tagged false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1OctetString getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
return getInstance(obj.getObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* return an Octet String from the given object.
|
||||
*
|
||||
* @param obj the object we want converted.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1OctetString getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1OctetString)
|
||||
{
|
||||
return (ASN1OctetString)obj;
|
||||
}
|
||||
|
||||
if (obj instanceof ASN1TaggedObject)
|
||||
{
|
||||
return getInstance(((ASN1TaggedObject)obj).getObject());
|
||||
}
|
||||
|
||||
if (obj instanceof ASN1Sequence)
|
||||
{
|
||||
Vector v = new Vector();
|
||||
Enumeration e = ((ASN1Sequence)obj).getObjects();
|
||||
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
v.addElement(e.nextElement());
|
||||
}
|
||||
|
||||
return new BERConstructedOctetString(v);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string the octets making up the octet string.
|
||||
*/
|
||||
public ASN1OctetString(
|
||||
byte[] string)
|
||||
{
|
||||
if (string == null)
|
||||
{
|
||||
throw new NullPointerException("string cannot be null");
|
||||
}
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
public ASN1OctetString(
|
||||
DEREncodable obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.string = obj.getDERObject().getEncoded(ASN1Encodable.DER);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("Error processing object : " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public InputStream getOctetStream()
|
||||
{
|
||||
return new ByteArrayInputStream(string);
|
||||
}
|
||||
|
||||
public ASN1OctetStringParser parser()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] getOctets()
|
||||
{
|
||||
return string;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(this.getOctets());
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
DERObject o)
|
||||
{
|
||||
if (!(o instanceof ASN1OctetString))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1OctetString other = (ASN1OctetString)o;
|
||||
|
||||
return Arrays.areEqual(string, other.string);
|
||||
}
|
||||
|
||||
abstract void encode(DEROutputStream out)
|
||||
throws IOException;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "#"+new String(Hex.encode(string));
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface ASN1OctetStringParser
|
||||
extends DEREncodable
|
||||
{
|
||||
public InputStream getOctetStream();
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class ASN1OutputStream
|
||||
extends DEROutputStream
|
||||
{
|
||||
public ASN1OutputStream(
|
||||
OutputStream os)
|
||||
{
|
||||
super(os);
|
||||
}
|
||||
|
||||
public void writeObject(
|
||||
Object obj)
|
||||
throws IOException
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
writeNull();
|
||||
}
|
||||
else if (obj instanceof DERObject)
|
||||
{
|
||||
((DERObject)obj).encode(this);
|
||||
}
|
||||
else if (obj instanceof DEREncodable)
|
||||
{
|
||||
((DEREncodable)obj).getDERObject().encode(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("object not ASN1Encodable");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
public abstract class ASN1Sequence
|
||||
extends ASN1Object
|
||||
{
|
||||
private Vector seq = new Vector();
|
||||
|
||||
/**
|
||||
* return an ASN1Sequence from the given object.
|
||||
*
|
||||
* @param obj the object we want converted.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1Sequence getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Sequence)
|
||||
{
|
||||
return (ASN1Sequence)obj;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ASN1 sequence from a tagged object. There is a special
|
||||
* case here, if an object appears to have been explicitly tagged on
|
||||
* reading but we were expecting it to be implicitly tagged in the
|
||||
* normal course of events it indicates that we lost the surrounding
|
||||
* sequence - so we need to add it back (this will happen if the tagged
|
||||
* object is a sequence that contains other sequences). If you are
|
||||
* dealing with implicitly tagged sequences you really <b>should</b>
|
||||
* be using this method.
|
||||
*
|
||||
* @param obj the tagged object.
|
||||
* @param explicit true if the object is meant to be explicitly tagged,
|
||||
* false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1Sequence getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
if (explicit)
|
||||
{
|
||||
if (!obj.isExplicit())
|
||||
{
|
||||
throw new IllegalArgumentException("object implicit - explicit expected.");
|
||||
}
|
||||
|
||||
return (ASN1Sequence)obj.getObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// constructed object which appears to be explicitly tagged
|
||||
// when it should be implicit means we have to add the
|
||||
// surrounding sequence.
|
||||
//
|
||||
if (obj.isExplicit())
|
||||
{
|
||||
if (obj instanceof BERTaggedObject)
|
||||
{
|
||||
return new BERSequence(obj.getObject());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new DERSequence(obj.getObject());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj.getObject() instanceof ASN1Sequence)
|
||||
{
|
||||
return (ASN1Sequence)obj.getObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
public Enumeration getObjects()
|
||||
{
|
||||
return seq.elements();
|
||||
}
|
||||
|
||||
public ASN1SequenceParser parser()
|
||||
{
|
||||
final ASN1Sequence outer = this;
|
||||
|
||||
return new ASN1SequenceParser()
|
||||
{
|
||||
private final int max = size();
|
||||
|
||||
private int index;
|
||||
|
||||
public DEREncodable readObject() throws IOException
|
||||
{
|
||||
if (index == max)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DEREncodable obj = getObjectAt(index++);
|
||||
if (obj instanceof ASN1Sequence)
|
||||
{
|
||||
return ((ASN1Sequence)obj).parser();
|
||||
}
|
||||
if (obj instanceof ASN1Set)
|
||||
{
|
||||
return ((ASN1Set)obj).parser();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
return outer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* return the object at the sequence position indicated by index.
|
||||
*
|
||||
* @param index the sequence number (starting at zero) of the object
|
||||
* @return the object at the sequence position indicated by index.
|
||||
*/
|
||||
public DEREncodable getObjectAt(
|
||||
int index)
|
||||
{
|
||||
return (DEREncodable)seq.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the number of objects in this sequence.
|
||||
*
|
||||
* @return the number of objects in this sequence.
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return seq.size();
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
Enumeration e = this.getObjects();
|
||||
int hashCode = size();
|
||||
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
Object o = e.nextElement();
|
||||
hashCode *= 17;
|
||||
if (o != null)
|
||||
{
|
||||
hashCode ^= o.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
DERObject o)
|
||||
{
|
||||
if (!(o instanceof ASN1Sequence))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1Sequence other = (ASN1Sequence)o;
|
||||
|
||||
if (this.size() != other.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration s1 = this.getObjects();
|
||||
Enumeration s2 = other.getObjects();
|
||||
|
||||
while (s1.hasMoreElements())
|
||||
{
|
||||
DERObject o1 = ((DEREncodable)s1.nextElement()).getDERObject();
|
||||
DERObject o2 = ((DEREncodable)s2.nextElement()).getDERObject();
|
||||
|
||||
if (o1 == o2 || (o1 != null && o1.equals(o2)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void addObject(
|
||||
DEREncodable obj)
|
||||
{
|
||||
seq.addElement(obj);
|
||||
}
|
||||
|
||||
abstract void encode(DEROutputStream out)
|
||||
throws IOException;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return seq.toString();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ASN1SequenceParser
|
||||
extends DEREncodable
|
||||
{
|
||||
DEREncodable readObject()
|
||||
throws IOException;
|
||||
}
|
|
@ -1,343 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
abstract public class ASN1Set
|
||||
extends ASN1Object
|
||||
{
|
||||
protected Vector set = new Vector();
|
||||
|
||||
/**
|
||||
* return an ASN1Set from the given object.
|
||||
*
|
||||
* @param obj the object we want converted.
|
||||
* @exception IllegalArgumentException if the object cannot be converted.
|
||||
*/
|
||||
public static ASN1Set getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1Set)
|
||||
{
|
||||
return (ASN1Set)obj;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an ASN1 set from a tagged object. There is a special
|
||||
* case here, if an object appears to have been explicitly tagged on
|
||||
* reading but we were expecting it to be implicitly tagged in the
|
||||
* normal course of events it indicates that we lost the surrounding
|
||||
* set - so we need to add it back (this will happen if the tagged
|
||||
* object is a sequence that contains other sequences). If you are
|
||||
* dealing with implicitly tagged sets you really <b>should</b>
|
||||
* be using this method.
|
||||
*
|
||||
* @param obj the tagged object.
|
||||
* @param explicit true if the object is meant to be explicitly tagged
|
||||
* false otherwise.
|
||||
* @exception IllegalArgumentException if the tagged object cannot
|
||||
* be converted.
|
||||
*/
|
||||
public static ASN1Set getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
if (explicit)
|
||||
{
|
||||
if (!obj.isExplicit())
|
||||
{
|
||||
throw new IllegalArgumentException("object implicit - explicit expected.");
|
||||
}
|
||||
|
||||
return (ASN1Set)obj.getObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// constructed object which appears to be explicitly tagged
|
||||
// and it's really implicit means we have to add the
|
||||
// surrounding sequence.
|
||||
//
|
||||
if (obj.isExplicit())
|
||||
{
|
||||
ASN1Set set = new DERSet(obj.getObject());
|
||||
|
||||
return set;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj.getObject() instanceof ASN1Set)
|
||||
{
|
||||
return (ASN1Set)obj.getObject();
|
||||
}
|
||||
|
||||
//
|
||||
// in this case the parser returns a sequence, convert it
|
||||
// into a set.
|
||||
//
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
|
||||
if (obj.getObject() instanceof ASN1Sequence)
|
||||
{
|
||||
ASN1Sequence s = (ASN1Sequence)obj.getObject();
|
||||
Enumeration e = s.getObjects();
|
||||
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
v.add((DEREncodable)e.nextElement());
|
||||
}
|
||||
|
||||
return new DERSet(v, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
public ASN1Set()
|
||||
{
|
||||
}
|
||||
|
||||
public Enumeration getObjects()
|
||||
{
|
||||
return set.elements();
|
||||
}
|
||||
|
||||
/**
|
||||
* return the object at the set position indicated by index.
|
||||
*
|
||||
* @param index the set number (starting at zero) of the object
|
||||
* @return the object at the set position indicated by index.
|
||||
*/
|
||||
public DEREncodable getObjectAt(
|
||||
int index)
|
||||
{
|
||||
return (DEREncodable)set.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the number of objects in this set.
|
||||
*
|
||||
* @return the number of objects in this set.
|
||||
*/
|
||||
public int size()
|
||||
{
|
||||
return set.size();
|
||||
}
|
||||
|
||||
public ASN1SetParser parser()
|
||||
{
|
||||
final ASN1Set outer = this;
|
||||
|
||||
return new ASN1SetParser()
|
||||
{
|
||||
private final int max = size();
|
||||
|
||||
private int index;
|
||||
|
||||
public DEREncodable readObject() throws IOException
|
||||
{
|
||||
if (index == max)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DEREncodable obj = getObjectAt(index++);
|
||||
if (obj instanceof ASN1Sequence)
|
||||
{
|
||||
return ((ASN1Sequence)obj).parser();
|
||||
}
|
||||
if (obj instanceof ASN1Set)
|
||||
{
|
||||
return ((ASN1Set)obj).parser();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
return outer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
Enumeration e = this.getObjects();
|
||||
int hashCode = size();
|
||||
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
Object o = e.nextElement();
|
||||
hashCode *= 17;
|
||||
if (o != null)
|
||||
{
|
||||
hashCode ^= o.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
DERObject o)
|
||||
{
|
||||
if (!(o instanceof ASN1Set))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1Set other = (ASN1Set)o;
|
||||
|
||||
if (this.size() != other.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Enumeration s1 = this.getObjects();
|
||||
Enumeration s2 = other.getObjects();
|
||||
|
||||
while (s1.hasMoreElements())
|
||||
{
|
||||
DERObject o1 = ((DEREncodable)s1.nextElement()).getDERObject();
|
||||
DERObject o2 = ((DEREncodable)s2.nextElement()).getDERObject();
|
||||
|
||||
if (o1 == o2 || (o1 != null && o1.equals(o2)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if a <= b (arrays are assumed padded with zeros).
|
||||
*/
|
||||
private boolean lessThanOrEqual(
|
||||
byte[] a,
|
||||
byte[] b)
|
||||
{
|
||||
if (a.length <= b.length)
|
||||
{
|
||||
for (int i = 0; i != a.length; i++)
|
||||
{
|
||||
int l = a[i] & 0xff;
|
||||
int r = b[i] & 0xff;
|
||||
|
||||
if (r > l)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (l > r)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i != b.length; i++)
|
||||
{
|
||||
int l = a[i] & 0xff;
|
||||
int r = b[i] & 0xff;
|
||||
|
||||
if (r > l)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (l > r)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getEncoded(
|
||||
DEREncodable obj)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
|
||||
|
||||
try
|
||||
{
|
||||
aOut.writeObject(obj);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("cannot encode object added to SET");
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
protected void sort()
|
||||
{
|
||||
if (set.size() > 1)
|
||||
{
|
||||
boolean swapped = true;
|
||||
int lastSwap = set.size() - 1;
|
||||
|
||||
while (swapped)
|
||||
{
|
||||
int index = 0;
|
||||
int swapIndex = 0;
|
||||
byte[] a = getEncoded((DEREncodable)set.elementAt(0));
|
||||
|
||||
swapped = false;
|
||||
|
||||
while (index != lastSwap)
|
||||
{
|
||||
byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1));
|
||||
|
||||
if (lessThanOrEqual(a, b))
|
||||
{
|
||||
a = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
Object o = set.elementAt(index);
|
||||
|
||||
set.setElementAt(set.elementAt(index + 1), index);
|
||||
set.setElementAt(o, index + 1);
|
||||
|
||||
swapped = true;
|
||||
swapIndex = index;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
lastSwap = swapIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void addObject(
|
||||
DEREncodable obj)
|
||||
{
|
||||
set.addElement(obj);
|
||||
}
|
||||
|
||||
abstract void encode(DEROutputStream out)
|
||||
throws IOException;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return set.toString();
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ASN1SetParser
|
||||
extends DEREncodable
|
||||
{
|
||||
public DEREncodable readObject()
|
||||
throws IOException;
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ASN1StreamParser
|
||||
{
|
||||
private final InputStream _in;
|
||||
private final int _limit;
|
||||
|
||||
public ASN1StreamParser(
|
||||
InputStream in)
|
||||
{
|
||||
this(in, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public ASN1StreamParser(
|
||||
InputStream in,
|
||||
int limit)
|
||||
{
|
||||
this._in = in;
|
||||
this._limit = limit;
|
||||
}
|
||||
|
||||
public ASN1StreamParser(
|
||||
byte[] encoding)
|
||||
{
|
||||
this(new ByteArrayInputStream(encoding), encoding.length);
|
||||
}
|
||||
|
||||
public DEREncodable readObject()
|
||||
throws IOException
|
||||
{
|
||||
int tag = _in.read();
|
||||
if (tag == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// turn of looking for "00" while we resolve the tag
|
||||
//
|
||||
set00Check(false);
|
||||
|
||||
//
|
||||
// calculate tag number
|
||||
//
|
||||
int tagNo = ASN1InputStream.readTagNumber(_in, tag);
|
||||
|
||||
boolean isConstructed = (tag & DERTags.CONSTRUCTED) != 0;
|
||||
|
||||
//
|
||||
// calculate length
|
||||
//
|
||||
int length = ASN1InputStream.readLength(_in, _limit);
|
||||
|
||||
if (length < 0) // indefinite length method
|
||||
{
|
||||
if (!isConstructed)
|
||||
{
|
||||
throw new IOException("indefinite length primitive encoding encountered");
|
||||
}
|
||||
|
||||
IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in);
|
||||
|
||||
if ((tag & DERTags.APPLICATION) != 0)
|
||||
{
|
||||
ASN1StreamParser sp = new ASN1StreamParser(indIn);
|
||||
|
||||
return new BERApplicationSpecificParser(tagNo, sp);
|
||||
}
|
||||
|
||||
if ((tag & DERTags.TAGGED) != 0)
|
||||
{
|
||||
return new BERTaggedObjectParser(tag, tagNo, indIn);
|
||||
}
|
||||
|
||||
ASN1StreamParser sp = new ASN1StreamParser(indIn);
|
||||
|
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo)
|
||||
{
|
||||
case DERTags.OCTET_STRING:
|
||||
return new BEROctetStringParser(sp);
|
||||
case DERTags.SEQUENCE:
|
||||
return new BERSequenceParser(sp);
|
||||
case DERTags.SET:
|
||||
return new BERSetParser(sp);
|
||||
default:
|
||||
throw new IOException("unknown BER object encountered");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
|
||||
|
||||
if ((tag & DERTags.APPLICATION) != 0)
|
||||
{
|
||||
return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
|
||||
}
|
||||
|
||||
if ((tag & DERTags.TAGGED) != 0)
|
||||
{
|
||||
return new BERTaggedObjectParser(tag, tagNo, defIn);
|
||||
}
|
||||
|
||||
if (isConstructed)
|
||||
{
|
||||
// TODO There are other tags that may be constructed (e.g. BIT_STRING)
|
||||
switch (tagNo)
|
||||
{
|
||||
case DERTags.OCTET_STRING:
|
||||
//
|
||||
// yes, people actually do this...
|
||||
//
|
||||
return new BEROctetStringParser(new ASN1StreamParser(defIn));
|
||||
case DERTags.SEQUENCE:
|
||||
return new DERSequenceParser(new ASN1StreamParser(defIn));
|
||||
case DERTags.SET:
|
||||
return new DERSetParser(new ASN1StreamParser(defIn));
|
||||
default:
|
||||
// TODO Add DERUnknownTagParser class?
|
||||
return new DERUnknownTag(true, tagNo, defIn.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
// Some primitive encodings can be handled by parsers too...
|
||||
switch (tagNo)
|
||||
{
|
||||
case DERTags.OCTET_STRING:
|
||||
return new DEROctetStringParser(defIn);
|
||||
}
|
||||
|
||||
return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void set00Check(boolean enabled)
|
||||
{
|
||||
if (_in instanceof IndefiniteLengthInputStream)
|
||||
{
|
||||
((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
ASN1EncodableVector readVector() throws IOException
|
||||
{
|
||||
ASN1EncodableVector v = new ASN1EncodableVector();
|
||||
|
||||
DEREncodable obj;
|
||||
while ((obj = readObject()) != null)
|
||||
{
|
||||
v.add(obj.getDERObject());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
|
||||
* a [n] where n is some number - these are assumed to follow the construction
|
||||
* rules (as with sequences).
|
||||
*/
|
||||
public abstract class ASN1TaggedObject
|
||||
extends ASN1Object
|
||||
implements ASN1TaggedObjectParser
|
||||
{
|
||||
int tagNo;
|
||||
boolean empty = false;
|
||||
boolean explicit = true;
|
||||
DEREncodable obj = null;
|
||||
|
||||
static public ASN1TaggedObject getInstance(
|
||||
ASN1TaggedObject obj,
|
||||
boolean explicit)
|
||||
{
|
||||
if (explicit)
|
||||
{
|
||||
return (ASN1TaggedObject)obj.getObject();
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("implicitly tagged tagged object");
|
||||
}
|
||||
|
||||
static public ASN1TaggedObject getInstance(
|
||||
Object obj)
|
||||
{
|
||||
if (obj == null || obj instanceof ASN1TaggedObject)
|
||||
{
|
||||
return (ASN1TaggedObject)obj;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tagged object in the explicit style.
|
||||
*
|
||||
* @param tagNo the tag number for this object.
|
||||
* @param obj the tagged object.
|
||||
*/
|
||||
public ASN1TaggedObject(
|
||||
int tagNo,
|
||||
DEREncodable obj)
|
||||
{
|
||||
this.explicit = true;
|
||||
this.tagNo = tagNo;
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tagged object with the style given by the value of explicit.
|
||||
* <p>
|
||||
* If the object implements ASN1Choice the tag style will always be changed
|
||||
* to explicit in accordance with the ASN.1 encoding rules.
|
||||
* </p>
|
||||
* @param explicit true if the object is explicitly tagged.
|
||||
* @param tagNo the tag number for this object.
|
||||
* @param obj the tagged object.
|
||||
*/
|
||||
public ASN1TaggedObject(
|
||||
boolean explicit,
|
||||
int tagNo,
|
||||
DEREncodable obj)
|
||||
{
|
||||
if (obj instanceof ASN1Choice)
|
||||
{
|
||||
this.explicit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.explicit = explicit;
|
||||
}
|
||||
|
||||
this.tagNo = tagNo;
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
boolean asn1Equals(
|
||||
DERObject o)
|
||||
{
|
||||
if (!(o instanceof ASN1TaggedObject))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1TaggedObject other = (ASN1TaggedObject)o;
|
||||
|
||||
if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(obj == null)
|
||||
{
|
||||
if (other.obj != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(obj.getDERObject().equals(other.obj.getDERObject())))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
int code = tagNo;
|
||||
|
||||
// TODO: actually this is wrong - the problem is that a re-encoded
|
||||
// object may end up with a different hashCode due to implicit
|
||||
// tagging. As implicit tagging is ambiguous if a sequence is involved
|
||||
// it seems the only correct method for both equals and hashCode is to
|
||||
// compare the encodings...
|
||||
if (obj != null)
|
||||
{
|
||||
code ^= obj.hashCode();
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
public int getTagNo()
|
||||
{
|
||||
return tagNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* return whether or not the object may be explicitly tagged.
|
||||
* <p>
|
||||
* Note: if the object has been read from an input stream, the only
|
||||
* time you can be sure if isExplicit is returning the true state of
|
||||
* affairs is if it returns false. An implicitly tagged object may appear
|
||||
* to be explicitly tagged, so you need to understand the context under
|
||||
* which the reading was done as well, see getObject below.
|
||||
*/
|
||||
public boolean isExplicit()
|
||||
{
|
||||
return explicit;
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
/**
|
||||
* return whatever was following the tag.
|
||||
* <p>
|
||||
* Note: tagged objects are generally context dependent if you're
|
||||
* trying to extract a tagged object you should be going via the
|
||||
* appropriate getInstance method.
|
||||
*/
|
||||
public DERObject getObject()
|
||||
{
|
||||
if (obj != null)
|
||||
{
|
||||
return obj.getDERObject();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object held in this tagged object as a parser assuming it has
|
||||
* the type of the passed in tag. If the object doesn't have a parser
|
||||
* associated with it, the base object is returned.
|
||||
*/
|
||||
public DEREncodable getObjectParser(
|
||||
int tag,
|
||||
boolean isExplicit)
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case DERTags.SET:
|
||||
return ASN1Set.getInstance(this, isExplicit).parser();
|
||||
case DERTags.SEQUENCE:
|
||||
return ASN1Sequence.getInstance(this, isExplicit).parser();
|
||||
case DERTags.OCTET_STRING:
|
||||
return ASN1OctetString.getInstance(this, isExplicit).parser();
|
||||
}
|
||||
|
||||
if (isExplicit)
|
||||
{
|
||||
return getObject();
|
||||
}
|
||||
|
||||
throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
|
||||
}
|
||||
|
||||
abstract void encode(DEROutputStream out)
|
||||
throws IOException;
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "[" + tagNo + "]" + obj;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface ASN1TaggedObjectParser
|
||||
extends DEREncodable
|
||||
{
|
||||
public int getTagNo();
|
||||
|
||||
public DEREncodable getObjectParser(int tag, boolean isExplicit)
|
||||
throws IOException;
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
public class BERApplicationSpecific
|
||||
extends DERApplicationSpecific
|
||||
{
|
||||
public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
|
||||
{
|
||||
super(tagNo, vec);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BERApplicationSpecificParser
|
||||
implements ASN1ApplicationSpecificParser
|
||||
{
|
||||
private final int tag;
|
||||
private final ASN1StreamParser parser;
|
||||
|
||||
BERApplicationSpecificParser(int tag, ASN1StreamParser parser)
|
||||
{
|
||||
this.tag = tag;
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public DEREncodable readObject()
|
||||
throws IOException
|
||||
{
|
||||
return parser.readObject();
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new BERApplicationSpecific(tag, parser.readVector());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Vector;
|
||||
|
||||
public class BERConstructedOctetString
|
||||
extends DEROctetString
|
||||
{
|
||||
private static final int MAX_LENGTH = 1000;
|
||||
|
||||
/**
|
||||
* convert a vector of octet strings into a single byte string
|
||||
*/
|
||||
static private byte[] toBytes(
|
||||
Vector octs)
|
||||
{
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
|
||||
for (int i = 0; i != octs.size(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
DEROctetString o = (DEROctetString)octs.elementAt(i);
|
||||
|
||||
bOut.write(o.getOctets());
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalArgumentException("exception converting octets " + e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return bOut.toByteArray();
|
||||
}
|
||||
|
||||
private Vector octs;
|
||||
|
||||
/**
|
||||
* @param string the octets making up the octet string.
|
||||
*/
|
||||
public BERConstructedOctetString(
|
||||
byte[] string)
|
||||
{
|
||||
super(string);
|
||||
}
|
||||
|
||||
public BERConstructedOctetString(
|
||||
Vector octs)
|
||||
{
|
||||
super(toBytes(octs));
|
||||
|
||||
this.octs = octs;
|
||||
}
|
||||
|
||||
public BERConstructedOctetString(
|
||||
DERObject obj)
|
||||
{
|
||||
super(obj);
|
||||
}
|
||||
|
||||
public BERConstructedOctetString(
|
||||
DEREncodable obj)
|
||||
{
|
||||
super(obj.getDERObject());
|
||||
}
|
||||
|
||||
public byte[] getOctets()
|
||||
{
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* return the DER octets that make up this string.
|
||||
*/
|
||||
public Enumeration getObjects()
|
||||
{
|
||||
if (octs == null)
|
||||
{
|
||||
return generateOcts().elements();
|
||||
}
|
||||
|
||||
return octs.elements();
|
||||
}
|
||||
|
||||
private Vector generateOcts()
|
||||
{
|
||||
Vector vec = new Vector();
|
||||
for (int i = 0; i < string.length; i += MAX_LENGTH)
|
||||
{
|
||||
int end;
|
||||
|
||||
if (i + MAX_LENGTH > string.length)
|
||||
{
|
||||
end = string.length;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = i + MAX_LENGTH;
|
||||
}
|
||||
|
||||
byte[] nStr = new byte[end - i];
|
||||
|
||||
System.arraycopy(string, i, nStr, 0, nStr.length);
|
||||
|
||||
vec.addElement(new DEROctetString(nStr));
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
public void encode(
|
||||
DEROutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
|
||||
{
|
||||
out.write(CONSTRUCTED | OCTET_STRING);
|
||||
|
||||
out.write(0x80);
|
||||
|
||||
//
|
||||
// write out the octet array
|
||||
//
|
||||
Enumeration e = getObjects();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
out.writeObject(e.nextElement());
|
||||
}
|
||||
|
||||
out.write(0x00);
|
||||
out.write(0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.encode(out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
class BERFactory
|
||||
{
|
||||
static final BERSequence EMPTY_SEQUENCE = new BERSequence();
|
||||
static final BERSet EMPTY_SET = new BERSet();
|
||||
|
||||
static BERSequence createSequence(ASN1EncodableVector v)
|
||||
{
|
||||
return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v);
|
||||
}
|
||||
|
||||
static BERSet createSet(ASN1EncodableVector v)
|
||||
{
|
||||
return v.size() < 1 ? EMPTY_SET : new BERSet(v);
|
||||
}
|
||||
|
||||
static BERSet createSet(ASN1EncodableVector v, boolean needsSorting)
|
||||
{
|
||||
return v.size() < 1 ? EMPTY_SET : new BERSet(v, needsSorting);
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BEROctetStringParser
|
||||
implements ASN1OctetStringParser
|
||||
{
|
||||
private ASN1StreamParser _parser;
|
||||
|
||||
BEROctetStringParser(
|
||||
ASN1StreamParser parser)
|
||||
{
|
||||
_parser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated will be removed
|
||||
*/
|
||||
protected BEROctetStringParser(
|
||||
ASN1ObjectParser parser)
|
||||
{
|
||||
_parser = parser._aIn;
|
||||
}
|
||||
|
||||
public InputStream getOctetStream()
|
||||
{
|
||||
return new ConstructedOctetStream(_parser);
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new BERConstructedOctetString(Streams.readAll(getOctetStream()));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException("IOException converting stream to byte array: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class BEROutputStream
|
||||
extends DEROutputStream
|
||||
{
|
||||
public BEROutputStream(
|
||||
OutputStream os)
|
||||
{
|
||||
super(os);
|
||||
}
|
||||
|
||||
public void writeObject(
|
||||
Object obj)
|
||||
throws IOException
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
writeNull();
|
||||
}
|
||||
else if (obj instanceof DERObject)
|
||||
{
|
||||
((DERObject)obj).encode(this);
|
||||
}
|
||||
else if (obj instanceof DEREncodable)
|
||||
{
|
||||
((DEREncodable)obj).getDERObject().encode(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("object not BEREncodable");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class BERSequence
|
||||
extends DERSequence
|
||||
{
|
||||
/**
|
||||
* create an empty sequence
|
||||
*/
|
||||
public BERSequence()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a sequence containing one object
|
||||
*/
|
||||
public BERSequence(
|
||||
DEREncodable obj)
|
||||
{
|
||||
super(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a sequence containing a vector of objects.
|
||||
*/
|
||||
public BERSequence(
|
||||
DEREncodableVector v)
|
||||
{
|
||||
super(v);
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
void encode(
|
||||
DEROutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
|
||||
{
|
||||
out.write(SEQUENCE | CONSTRUCTED);
|
||||
out.write(0x80);
|
||||
|
||||
Enumeration e = getObjects();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
out.writeObject(e.nextElement());
|
||||
}
|
||||
|
||||
out.write(0x00);
|
||||
out.write(0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.encode(out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BERSequenceParser
|
||||
implements ASN1SequenceParser
|
||||
{
|
||||
private ASN1StreamParser _parser;
|
||||
|
||||
BERSequenceParser(ASN1StreamParser parser)
|
||||
{
|
||||
this._parser = parser;
|
||||
}
|
||||
|
||||
public DEREncodable readObject()
|
||||
throws IOException
|
||||
{
|
||||
return _parser.readObject();
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new BERSequence(_parser.readVector());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class BERSet
|
||||
extends DERSet
|
||||
{
|
||||
/**
|
||||
* create an empty sequence
|
||||
*/
|
||||
public BERSet()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* create a set containing one object
|
||||
*/
|
||||
public BERSet(
|
||||
DEREncodable obj)
|
||||
{
|
||||
super(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param v - a vector of objects making up the set.
|
||||
*/
|
||||
public BERSet(
|
||||
DEREncodableVector v)
|
||||
{
|
||||
super(v, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param v - a vector of objects making up the set.
|
||||
*/
|
||||
BERSet(
|
||||
DEREncodableVector v,
|
||||
boolean needsSorting)
|
||||
{
|
||||
super(v, needsSorting);
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
void encode(
|
||||
DEROutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
if (out instanceof ASN1OutputStream || out instanceof BEROutputStream)
|
||||
{
|
||||
out.write(SET | CONSTRUCTED);
|
||||
out.write(0x80);
|
||||
|
||||
Enumeration e = getObjects();
|
||||
while (e.hasMoreElements())
|
||||
{
|
||||
out.writeObject(e.nextElement());
|
||||
}
|
||||
|
||||
out.write(0x00);
|
||||
out.write(0x00);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.encode(out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package org.thoughtcrime.bouncycastle.asn1;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BERSetParser
|
||||
implements ASN1SetParser
|
||||
{
|
||||
private ASN1StreamParser _parser;
|
||||
|
||||
BERSetParser(ASN1StreamParser parser)
|
||||
{
|
||||
this._parser = parser;
|
||||
}
|
||||
|
||||
public DEREncodable readObject()
|
||||
throws IOException
|
||||
{
|
||||
return _parser.readObject();
|
||||
}
|
||||
|
||||
public DERObject getDERObject()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new BERSet(_parser.readVector(), false);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new IllegalStateException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue