diff options
author | David Hook <dgh@cryptoworkshop.com> | 2013-05-17 03:53:06 +0400 |
---|---|---|
committer | David Hook <dgh@cryptoworkshop.com> | 2013-05-17 03:53:06 +0400 |
commit | 60653dba5719e4d60038194c6a4ca558558fe1dc (patch) | |
tree | 5d3fc31323fe0c0384953b733823f2b22d5936d9 | |
parent | 26662a93f7283d426d325d472173f4369108375e (diff) |
fixed line endings.
16 files changed, 3425 insertions, 3425 deletions
diff --git a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index 4d6df7a3..98f46a6d 100644 --- a/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -1,42 +1,42 @@ -package org.bouncycastle.asn1;
-
-public class ASN1ObjectIdentifier
- extends DERObjectIdentifier
-{
- public ASN1ObjectIdentifier(String identifier)
- {
- super(identifier);
- }
-
- ASN1ObjectIdentifier(byte[] bytes)
- {
- super(bytes);
- }
-
- ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch)
- {
- super(oid, branch);
- }
-
- /**
- * Return an OID that creates a branch under the current one.
- *
- * @param branchID node numbers for the new branch.
- * @return the OID for the new created branch.
- */
- public ASN1ObjectIdentifier branch(String branchID)
- {
- return new ASN1ObjectIdentifier(this, branchID);
- }
-
- /**
- * Return true if this oid is an extension of the passed in branch, stem.
- * @param stem the arc or branch that is a possible parent.
- * @return true if the branch is on the passed in stem, false otherwise.
- */
- public boolean on(ASN1ObjectIdentifier stem)
- {
- String id = getId(), stemId = stem.getId();
- return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
- }
-}
+package org.bouncycastle.asn1; + +public class ASN1ObjectIdentifier + extends DERObjectIdentifier +{ + public ASN1ObjectIdentifier(String identifier) + { + super(identifier); + } + + ASN1ObjectIdentifier(byte[] bytes) + { + super(bytes); + } + + ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch) + { + super(oid, branch); + } + + /** + * Return an OID that creates a branch under the current one. + * + * @param branchID node numbers for the new branch. + * @return the OID for the new created branch. + */ + public ASN1ObjectIdentifier branch(String branchID) + { + return new ASN1ObjectIdentifier(this, branchID); + } + + /** + * Return true if this oid is an extension of the passed in branch, stem. + * @param stem the arc or branch that is a possible parent. + * @return true if the branch is on the passed in stem, false otherwise. + */ + public boolean on(ASN1ObjectIdentifier stem) + { + String id = getId(), stemId = stem.getId(); + return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId); + } +} diff --git a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java index 4f320b30..418f991b 100644 --- a/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java +++ b/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java @@ -1,425 +1,425 @@ -package org.bouncycastle.asn1;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-
-import org.bouncycastle.util.Arrays;
-
-public class DERObjectIdentifier
- extends ASN1Primitive
-{
- String identifier;
-
- private byte[] body;
-
- /**
- * return an OID from the passed in object
- *
- * @exception IllegalArgumentException if the object cannot be converted.
- */
- public static ASN1ObjectIdentifier getInstance(
- Object obj)
- {
- if (obj == null || obj instanceof ASN1ObjectIdentifier)
- {
- return (ASN1ObjectIdentifier)obj;
- }
-
- if (obj instanceof DERObjectIdentifier)
- {
- return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId());
- }
-
- if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier)
- {
- return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive();
- }
-
- if (obj instanceof byte[])
- {
- return ASN1ObjectIdentifier.fromOctetString((byte[])obj);
- }
-
- throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
- }
-
- /**
- * return an Object Identifier 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 ASN1ObjectIdentifier getInstance(
- ASN1TaggedObject obj,
- boolean explicit)
- {
- ASN1Primitive o = obj.getObject();
-
- if (explicit || o instanceof DERObjectIdentifier)
- {
- return getInstance(o);
- }
- else
- {
- return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets());
- }
- }
-
- private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f;
-
- DERObjectIdentifier(
- byte[] bytes)
- {
- StringBuffer objId = new StringBuffer();
- long value = 0;
- BigInteger bigValue = null;
- boolean first = true;
-
- for (int i = 0; i != bytes.length; i++)
- {
- int b = bytes[i] & 0xff;
-
- if (value <= LONG_LIMIT)
- {
- value += (b & 0x7f);
- if ((b & 0x80) == 0) // end of number reached
- {
- if (first)
- {
- if (value < 40)
- {
- objId.append('0');
- }
- else if (value < 80)
- {
- objId.append('1');
- value -= 40;
- }
- else
- {
- objId.append('2');
- value -= 80;
- }
- first = false;
- }
-
- objId.append('.');
- objId.append(value);
- value = 0;
- }
- else
- {
- value <<= 7;
- }
- }
- else
- {
- if (bigValue == null)
- {
- bigValue = BigInteger.valueOf(value);
- }
- bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
- if ((b & 0x80) == 0)
- {
- if (first)
- {
- objId.append('2');
- bigValue = bigValue.subtract(BigInteger.valueOf(80));
- first = false;
- }
-
- objId.append('.');
- objId.append(bigValue);
- bigValue = null;
- value = 0;
- }
- else
- {
- bigValue = bigValue.shiftLeft(7);
- }
- }
- }
-
- this.identifier = objId.toString();
- this.body = Arrays.clone(bytes);
- }
-
- public DERObjectIdentifier(
- String identifier)
- {
- if (identifier == null)
- {
- throw new IllegalArgumentException("'identifier' cannot be null");
- }
- if (!isValidIdentifier(identifier))
- {
- throw new IllegalArgumentException("string " + identifier + " not an OID");
- }
-
- this.identifier = identifier;
- }
-
- DERObjectIdentifier(DERObjectIdentifier oid, String branchID)
- {
- if (!isValidBranchID(branchID, 0))
- {
- throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
- }
-
- this.identifier = oid.getId() + "." + branchID;
- }
-
- public String getId()
- {
- return identifier;
- }
-
- private void writeField(
- ByteArrayOutputStream out,
- long fieldValue)
- {
- byte[] result = new byte[9];
- int pos = 8;
- result[pos] = (byte)((int)fieldValue & 0x7f);
- while (fieldValue >= (1L << 7))
- {
- fieldValue >>= 7;
- result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80);
- }
- out.write(result, pos, 9 - pos);
- }
-
- private void writeField(
- ByteArrayOutputStream out,
- BigInteger fieldValue)
- {
- int byteCount = (fieldValue.bitLength()+6)/7;
- if (byteCount == 0)
- {
- out.write(0);
- }
- else
- {
- BigInteger tmpValue = fieldValue;
- byte[] tmp = new byte[byteCount];
- for (int i = byteCount-1; i >= 0; i--)
- {
- tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
- tmpValue = tmpValue.shiftRight(7);
- }
- tmp[byteCount-1] &= 0x7f;
- out.write(tmp, 0, tmp.length);
- }
- }
-
- private void doOutput(ByteArrayOutputStream aOut)
- {
- OIDTokenizer tok = new OIDTokenizer(identifier);
- int first = Integer.parseInt(tok.nextToken()) * 40;
-
- String secondToken = tok.nextToken();
- if (secondToken.length() <= 18)
- {
- writeField(aOut, first + Long.parseLong(secondToken));
- }
- else
- {
- writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first)));
- }
-
- while (tok.hasMoreTokens())
- {
- String token = tok.nextToken();
- if (token.length() <= 18)
- {
- writeField(aOut, Long.parseLong(token));
- }
- else
- {
- writeField(aOut, new BigInteger(token));
- }
- }
- }
-
- protected synchronized byte[] getBody()
- {
- if (body == null)
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
-
- doOutput(bOut);
-
- body = bOut.toByteArray();
- }
-
- return body;
- }
-
- boolean isConstructed()
- {
- return false;
- }
-
- int encodedLength()
- throws IOException
- {
- int length = getBody().length;
-
- return 1 + StreamUtil.calculateBodyLength(length) + length;
- }
-
- void encode(
- ASN1OutputStream out)
- throws IOException
- {
- byte[] enc = getBody();
-
- out.write(BERTags.OBJECT_IDENTIFIER);
- out.writeLength(enc.length);
- out.write(enc);
- }
-
- public int hashCode()
- {
- return identifier.hashCode();
- }
-
- boolean asn1Equals(
- ASN1Primitive o)
- {
- if (!(o instanceof DERObjectIdentifier))
- {
- return false;
- }
-
- return identifier.equals(((DERObjectIdentifier)o).identifier);
- }
-
- public String toString()
- {
- return getId();
- }
-
- private static boolean isValidBranchID(
- String branchID, int start)
- {
- boolean periodAllowed = false;
-
- int pos = branchID.length();
- while (--pos >= start)
- {
- char ch = branchID.charAt(pos);
-
- // TODO Leading zeroes?
- if ('0' <= ch && ch <= '9')
- {
- periodAllowed = true;
- continue;
- }
-
- if (ch == '.')
- {
- if (!periodAllowed)
- {
- return false;
- }
-
- periodAllowed = false;
- continue;
- }
-
- return false;
- }
-
- return periodAllowed;
- }
-
- private static boolean isValidIdentifier(
- String identifier)
- {
- if (identifier.length() < 3 || identifier.charAt(1) != '.')
- {
- return false;
- }
-
- char first = identifier.charAt(0);
- if (first < '0' || first > '2')
- {
- return false;
- }
-
- return isValidBranchID(identifier, 2);
- }
-
- private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][];
-
- static ASN1ObjectIdentifier fromOctetString(byte[] enc)
- {
- if (enc.length < 3)
- {
- return new ASN1ObjectIdentifier(enc);
- }
-
- int idx1 = enc[enc.length - 2] & 0xff;
- // in this case top bit is always zero
- int idx2 = enc[enc.length - 1] & 0x7f;
-
- ASN1ObjectIdentifier possibleMatch;
-
- synchronized (cache)
- {
- ASN1ObjectIdentifier[] first = cache[idx1];
- if (first == null)
- {
- first = cache[idx1] = new ASN1ObjectIdentifier[128];
- }
-
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- idx1 = (idx1 + 1) & 0xff;
- first = cache[idx1];
- if (first == null)
- {
- first = cache[idx1] = new ASN1ObjectIdentifier[128];
- }
-
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- idx2 = (idx2 + 1) & 0x7f;
- possibleMatch = first[idx2];
- if (possibleMatch == null)
- {
- return first[idx2] = new ASN1ObjectIdentifier(enc);
- }
- }
-
- if (Arrays.areEqual(enc, possibleMatch.getBody()))
- {
- return possibleMatch;
- }
-
- return new ASN1ObjectIdentifier(enc);
- }
-}
+package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; + +public class DERObjectIdentifier + extends ASN1Primitive +{ + String identifier; + + private byte[] body; + + /** + * return an OID from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1ObjectIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)obj; + } + + if (obj instanceof DERObjectIdentifier) + { + return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId()); + } + + if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + } + + if (obj instanceof byte[]) + { + return ASN1ObjectIdentifier.fromOctetString((byte[])obj); + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Object Identifier 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 ASN1ObjectIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERObjectIdentifier) + { + return getInstance(o); + } + else + { + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; + + DERObjectIdentifier( + byte[] bytes) + { + StringBuffer objId = new StringBuffer(); + long value = 0; + BigInteger bigValue = null; + boolean first = true; + + for (int i = 0; i != bytes.length; i++) + { + int b = bytes[i] & 0xff; + + if (value <= LONG_LIMIT) + { + value += (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + if (value < 40) + { + objId.append('0'); + } + else if (value < 80) + { + objId.append('1'); + value -= 40; + } + else + { + objId.append('2'); + value -= 80; + } + first = false; + } + + objId.append('.'); + objId.append(value); + value = 0; + } + else + { + value <<= 7; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.valueOf(value); + } + bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); + if ((b & 0x80) == 0) + { + if (first) + { + objId.append('2'); + bigValue = bigValue.subtract(BigInteger.valueOf(80)); + first = false; + } + + objId.append('.'); + objId.append(bigValue); + bigValue = null; + value = 0; + } + else + { + bigValue = bigValue.shiftLeft(7); + } + } + } + + this.identifier = objId.toString(); + this.body = Arrays.clone(bytes); + } + + public DERObjectIdentifier( + String identifier) + { + if (identifier == null) + { + throw new IllegalArgumentException("'identifier' cannot be null"); + } + if (!isValidIdentifier(identifier)) + { + throw new IllegalArgumentException("string " + identifier + " not an OID"); + } + + this.identifier = identifier; + } + + DERObjectIdentifier(DERObjectIdentifier oid, String branchID) + { + if (!isValidBranchID(branchID, 0)) + { + throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); + } + + this.identifier = oid.getId() + "." + branchID; + } + + public String getId() + { + return identifier; + } + + private void writeField( + ByteArrayOutputStream out, + long fieldValue) + { + byte[] result = new byte[9]; + int pos = 8; + result[pos] = (byte)((int)fieldValue & 0x7f); + while (fieldValue >= (1L << 7)) + { + fieldValue >>= 7; + result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); + } + out.write(result, pos, 9 - pos); + } + + private void writeField( + ByteArrayOutputStream out, + BigInteger fieldValue) + { + int byteCount = (fieldValue.bitLength()+6)/7; + if (byteCount == 0) + { + out.write(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount-1; i >= 0; i--) + { + tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80); + tmpValue = tmpValue.shiftRight(7); + } + tmp[byteCount-1] &= 0x7f; + out.write(tmp, 0, tmp.length); + } + } + + private void doOutput(ByteArrayOutputStream aOut) + { + OIDTokenizer tok = new OIDTokenizer(identifier); + int first = Integer.parseInt(tok.nextToken()) * 40; + + String secondToken = tok.nextToken(); + if (secondToken.length() <= 18) + { + writeField(aOut, first + Long.parseLong(secondToken)); + } + else + { + writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); + } + + while (tok.hasMoreTokens()) + { + String token = tok.nextToken(); + if (token.length() <= 18) + { + writeField(aOut, Long.parseLong(token)); + } + else + { + writeField(aOut, new BigInteger(token)); + } + } + } + + protected synchronized byte[] getBody() + { + if (body == null) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + doOutput(bOut); + + body = bOut.toByteArray(); + } + + return body; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + throws IOException + { + int length = getBody().length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] enc = getBody(); + + out.write(BERTags.OBJECT_IDENTIFIER); + out.writeLength(enc.length); + out.write(enc); + } + + public int hashCode() + { + return identifier.hashCode(); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERObjectIdentifier)) + { + return false; + } + + return identifier.equals(((DERObjectIdentifier)o).identifier); + } + + public String toString() + { + return getId(); + } + + private static boolean isValidBranchID( + String branchID, int start) + { + boolean periodAllowed = false; + + int pos = branchID.length(); + while (--pos >= start) + { + char ch = branchID.charAt(pos); + + // TODO Leading zeroes? + if ('0' <= ch && ch <= '9') + { + periodAllowed = true; + continue; + } + + if (ch == '.') + { + if (!periodAllowed) + { + return false; + } + + periodAllowed = false; + continue; + } + + return false; + } + + return periodAllowed; + } + + private static boolean isValidIdentifier( + String identifier) + { + if (identifier.length() < 3 || identifier.charAt(1) != '.') + { + return false; + } + + char first = identifier.charAt(0); + if (first < '0' || first > '2') + { + return false; + } + + return isValidBranchID(identifier, 2); + } + + private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][]; + + static ASN1ObjectIdentifier fromOctetString(byte[] enc) + { + if (enc.length < 3) + { + return new ASN1ObjectIdentifier(enc); + } + + int idx1 = enc[enc.length - 2] & 0xff; + // in this case top bit is always zero + int idx2 = enc[enc.length - 1] & 0x7f; + + ASN1ObjectIdentifier possibleMatch; + + synchronized (cache) + { + ASN1ObjectIdentifier[] first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx1 = (idx1 + 1) & 0xff; + first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx2 = (idx2 + 1) & 0x7f; + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + return new ASN1ObjectIdentifier(enc); + } +} diff --git a/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java b/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java index 86873cec..1e2e0723 100644 --- a/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java +++ b/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java @@ -1,391 +1,391 @@ -package org.bouncycastle.bcpg;
-
-import org.bouncycastle.util.io.Streams;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * reader for PGP objects
- */
-public class BCPGInputStream
- extends InputStream implements PacketTags
-{
- InputStream in;
- boolean next = false;
- int nextB;
-
- public BCPGInputStream(
- InputStream in)
- {
- this.in = in;
- }
-
- public int available()
- throws IOException
- {
- return in.available();
- }
-
- public int read()
- throws IOException
- {
- if (next)
- {
- next = false;
-
- return nextB;
- }
- else
- {
- return in.read();
- }
- }
-
- public int read(
- byte[] buf,
- int off,
- int len)
- throws IOException
- {
- if (len == 0)
- {
- return 0;
- }
-
- if (!next)
- {
- return in.read(buf, off, len);
- }
-
- // We have next byte waiting, so return it
-
- if (nextB < 0)
- {
- return -1; // EOF
- }
-
- buf[off] = (byte)nextB; // May throw NullPointerException...
- next = false; // ...so only set this afterwards
-
- return 1;
- }
-
- public void readFully(
- byte[] buf,
- int off,
- int len)
- throws IOException
- {
- if (Streams.readFully(this, buf, off, len) < len)
- {
- throw new EOFException();
- }
- }
-
- public byte[] readAll()
- throws IOException
- {
- return Streams.readAll(this);
- }
-
- public void readFully(
- byte[] buf)
- throws IOException
- {
- readFully(buf, 0, buf.length);
- }
-
- /**
- * returns the next packet tag in the stream.
- *
- * @return the tag number.
- *
- * @throws IOException
- */
- public int nextPacketTag()
- throws IOException
- {
- if (!next)
- {
- try
- {
- nextB = in.read();
- }
- catch (EOFException e)
- {
- nextB = -1;
- }
- }
-
- next = true;
-
- if (nextB >= 0)
- {
- if ((nextB & 0x40) != 0) // new
- {
- return (nextB & 0x3f);
- }
- else // old
- {
- return ((nextB & 0x3f) >> 2);
- }
- }
-
- return nextB;
- }
-
- public Packet readPacket()
- throws IOException
- {
- int hdr = this.read();
-
- if (hdr < 0)
- {
- return null;
- }
-
- if ((hdr & 0x80) == 0)
- {
- throw new IOException("invalid header encountered");
- }
-
- boolean newPacket = (hdr & 0x40) != 0;
- int tag = 0;
- int bodyLen = 0;
- boolean partial = false;
-
- if (newPacket)
- {
- tag = hdr & 0x3f;
-
- int l = this.read();
-
- if (l < 192)
- {
- bodyLen = l;
- }
- else if (l <= 223)
- {
- int b = in.read();
-
- bodyLen = ((l - 192) << 8) + (b) + 192;
- }
- else if (l == 255)
- {
- bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read();
- }
- else
- {
- partial = true;
- bodyLen = 1 << (l & 0x1f);
- }
- }
- else
- {
- int lengthType = hdr & 0x3;
-
- tag = (hdr & 0x3f) >> 2;
-
- switch (lengthType)
- {
- case 0:
- bodyLen = this.read();
- break;
- case 1:
- bodyLen = (this.read() << 8) | this.read();
- break;
- case 2:
- bodyLen = (this.read() << 24) | (this.read() << 16) | (this.read() << 8) | this.read();
- break;
- case 3:
- partial = true;
- break;
- default:
- throw new IOException("unknown length type encountered");
- }
- }
-
- BCPGInputStream objStream;
-
- if (bodyLen == 0 && partial)
- {
- objStream = this;
- }
- else
- {
- objStream = new BCPGInputStream(new PartialInputStream(this, partial, bodyLen));
- }
-
- switch (tag)
- {
- case RESERVED:
- return new InputStreamPacket(objStream);
- case PUBLIC_KEY_ENC_SESSION:
- return new PublicKeyEncSessionPacket(objStream);
- case SIGNATURE:
- return new SignaturePacket(objStream);
- case SYMMETRIC_KEY_ENC_SESSION:
- return new SymmetricKeyEncSessionPacket(objStream);
- case ONE_PASS_SIGNATURE:
- return new OnePassSignaturePacket(objStream);
- case SECRET_KEY:
- return new SecretKeyPacket(objStream);
- case PUBLIC_KEY:
- return new PublicKeyPacket(objStream);
- case SECRET_SUBKEY:
- return new SecretSubkeyPacket(objStream);
- case COMPRESSED_DATA:
- return new CompressedDataPacket(objStream);
- case SYMMETRIC_KEY_ENC:
- return new SymmetricEncDataPacket(objStream);
- case MARKER:
- return new MarkerPacket(objStream);
- case LITERAL_DATA:
- return new LiteralDataPacket(objStream);
- case TRUST:
- return new TrustPacket(objStream);
- case USER_ID:
- return new UserIDPacket(objStream);
- case USER_ATTRIBUTE:
- return new UserAttributePacket(objStream);
- case PUBLIC_SUBKEY:
- return new PublicSubkeyPacket(objStream);
- case SYM_ENC_INTEGRITY_PRO:
- return new SymmetricEncIntegrityPacket(objStream);
- case MOD_DETECTION_CODE:
- return new ModDetectionCodePacket(objStream);
- case EXPERIMENTAL_1:
- case EXPERIMENTAL_2:
- case EXPERIMENTAL_3:
- case EXPERIMENTAL_4:
- return new ExperimentalPacket(tag, objStream);
- default:
- throw new IOException("unknown packet type encountered: " + tag);
- }
- }
-
- public void close()
- throws IOException
- {
- in.close();
- }
-
- /**
- * a stream that overlays our input stream, allowing the user to only read a segment of it.
- *
- * NB: dataLength will be negative if the segment length is in the upper range above 2**31.
- */
- private static class PartialInputStream
- extends InputStream
- {
- private BCPGInputStream in;
- private boolean partial;
- private int dataLength;
-
- PartialInputStream(
- BCPGInputStream in,
- boolean partial,
- int dataLength)
- {
- this.in = in;
- this.partial = partial;
- this.dataLength = dataLength;
- }
-
- public int available()
- throws IOException
- {
- int avail = in.available();
-
- if (avail <= dataLength || dataLength < 0)
- {
- return avail;
- }
- else
- {
- if (partial && dataLength == 0)
- {
- return 1;
- }
- return dataLength;
- }
- }
-
- private int loadDataLength()
- throws IOException
- {
- int l = in.read();
-
- if (l < 0)
- {
- return -1;
- }
-
- partial = false;
- if (l < 192)
- {
- dataLength = l;
- }
- else if (l <= 223)
- {
- dataLength = ((l - 192) << 8) + (in.read()) + 192;
- }
- else if (l == 255)
- {
- dataLength = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read();
- }
- else
- {
- partial = true;
- dataLength = 1 << (l & 0x1f);
- }
-
- return dataLength;
- }
-
- public int read(byte[] buf, int offset, int len)
- throws IOException
- {
- do
- {
- if (dataLength != 0)
- {
- int readLen = (dataLength > len || dataLength < 0) ? len : dataLength;
- readLen = in.read(buf, offset, readLen);
- if (readLen < 0)
- {
- throw new EOFException("premature end of stream in PartialInputStream");
- }
- dataLength -= readLen;
- return readLen;
- }
- }
- while (partial && loadDataLength() >= 0);
-
- return -1;
- }
-
- public int read()
- throws IOException
- {
- do
- {
- if (dataLength != 0)
- {
- int ch = in.read();
- if (ch < 0)
- {
- throw new EOFException("premature end of stream in PartialInputStream");
- }
- dataLength--;
- return ch;
- }
- }
- while (partial && loadDataLength() >= 0);
-
- return -1;
- }
- }
-}
+package org.bouncycastle.bcpg; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.io.Streams; + +/** + * reader for PGP objects + */ +public class BCPGInputStream + extends InputStream implements PacketTags +{ + InputStream in; + boolean next = false; + int nextB; + + public BCPGInputStream( + InputStream in) + { + this.in = in; + } + + public int available() + throws IOException + { + return in.available(); + } + + public int read() + throws IOException + { + if (next) + { + next = false; + + return nextB; + } + else + { + return in.read(); + } + } + + public int read( + byte[] buf, + int off, + int len) + throws IOException + { + if (len == 0) + { + return 0; + } + + if (!next) + { + return in.read(buf, off, len); + } + + // We have next byte waiting, so return it + + if (nextB < 0) + { + return -1; // EOF + } + + buf[off] = (byte)nextB; // May throw NullPointerException... + next = false; // ...so only set this afterwards + + return 1; + } + + public void readFully( + byte[] buf, + int off, + int len) + throws IOException + { + if (Streams.readFully(this, buf, off, len) < len) + { + throw new EOFException(); + } + } + + public byte[] readAll() + throws IOException + { + return Streams.readAll(this); + } + + public void readFully( + byte[] buf) + throws IOException + { + readFully(buf, 0, buf.length); + } + + /** + * returns the next packet tag in the stream. + * + * @return the tag number. + * + * @throws IOException + */ + public int nextPacketTag() + throws IOException + { + if (!next) + { + try + { + nextB = in.read(); + } + catch (EOFException e) + { + nextB = -1; + } + } + + next = true; + + if (nextB >= 0) + { + if ((nextB & 0x40) != 0) // new + { + return (nextB & 0x3f); + } + else // old + { + return ((nextB & 0x3f) >> 2); + } + } + + return nextB; + } + + public Packet readPacket() + throws IOException + { + int hdr = this.read(); + + if (hdr < 0) + { + return null; + } + + if ((hdr & 0x80) == 0) + { + throw new IOException("invalid header encountered"); + } + + boolean newPacket = (hdr & 0x40) != 0; + int tag = 0; + int bodyLen = 0; + boolean partial = false; + + if (newPacket) + { + tag = hdr & 0x3f; + + int l = this.read(); + + if (l < 192) + { + bodyLen = l; + } + else if (l <= 223) + { + int b = in.read(); + + bodyLen = ((l - 192) << 8) + (b) + 192; + } + else if (l == 255) + { + bodyLen = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + partial = true; + bodyLen = 1 << (l & 0x1f); + } + } + else + { + int lengthType = hdr & 0x3; + + tag = (hdr & 0x3f) >> 2; + + switch (lengthType) + { + case 0: + bodyLen = this.read(); + break; + case 1: + bodyLen = (this.read() << 8) | this.read(); + break; + case 2: + bodyLen = (this.read() << 24) | (this.read() << 16) | (this.read() << 8) | this.read(); + break; + case 3: + partial = true; + break; + default: + throw new IOException("unknown length type encountered"); + } + } + + BCPGInputStream objStream; + + if (bodyLen == 0 && partial) + { + objStream = this; + } + else + { + objStream = new BCPGInputStream(new PartialInputStream(this, partial, bodyLen)); + } + + switch (tag) + { + case RESERVED: + return new InputStreamPacket(objStream); + case PUBLIC_KEY_ENC_SESSION: + return new PublicKeyEncSessionPacket(objStream); + case SIGNATURE: + return new SignaturePacket(objStream); + case SYMMETRIC_KEY_ENC_SESSION: + return new SymmetricKeyEncSessionPacket(objStream); + case ONE_PASS_SIGNATURE: + return new OnePassSignaturePacket(objStream); + case SECRET_KEY: + return new SecretKeyPacket(objStream); + case PUBLIC_KEY: + return new PublicKeyPacket(objStream); + case SECRET_SUBKEY: + return new SecretSubkeyPacket(objStream); + case COMPRESSED_DATA: + return new CompressedDataPacket(objStream); + case SYMMETRIC_KEY_ENC: + return new SymmetricEncDataPacket(objStream); + case MARKER: + return new MarkerPacket(objStream); + case LITERAL_DATA: + return new LiteralDataPacket(objStream); + case TRUST: + return new TrustPacket(objStream); + case USER_ID: + return new UserIDPacket(objStream); + case USER_ATTRIBUTE: + return new UserAttributePacket(objStream); + case PUBLIC_SUBKEY: + return new PublicSubkeyPacket(objStream); + case SYM_ENC_INTEGRITY_PRO: + return new SymmetricEncIntegrityPacket(objStream); + case MOD_DETECTION_CODE: + return new ModDetectionCodePacket(objStream); + case EXPERIMENTAL_1: + case EXPERIMENTAL_2: + case EXPERIMENTAL_3: + case EXPERIMENTAL_4: + return new ExperimentalPacket(tag, objStream); + default: + throw new IOException("unknown packet type encountered: " + tag); + } + } + + public void close() + throws IOException + { + in.close(); + } + + /** + * a stream that overlays our input stream, allowing the user to only read a segment of it. + * + * NB: dataLength will be negative if the segment length is in the upper range above 2**31. + */ + private static class PartialInputStream + extends InputStream + { + private BCPGInputStream in; + private boolean partial; + private int dataLength; + + PartialInputStream( + BCPGInputStream in, + boolean partial, + int dataLength) + { + this.in = in; + this.partial = partial; + this.dataLength = dataLength; + } + + public int available() + throws IOException + { + int avail = in.available(); + + if (avail <= dataLength || dataLength < 0) + { + return avail; + } + else + { + if (partial && dataLength == 0) + { + return 1; + } + return dataLength; + } + } + + private int loadDataLength() + throws IOException + { + int l = in.read(); + + if (l < 0) + { + return -1; + } + + partial = false; + if (l < 192) + { + dataLength = l; + } + else if (l <= 223) + { + dataLength = ((l - 192) << 8) + (in.read()) + 192; + } + else if (l == 255) + { + dataLength = (in.read() << 24) | (in.read() << 16) | (in.read() << 8) | in.read(); + } + else + { + partial = true; + dataLength = 1 << (l & 0x1f); + } + + return dataLength; + } + + public int read(byte[] buf, int offset, int len) + throws IOException + { + do + { + if (dataLength != 0) + { + int readLen = (dataLength > len || dataLength < 0) ? len : dataLength; + readLen = in.read(buf, offset, readLen); + if (readLen < 0) + { + throw new EOFException("premature end of stream in PartialInputStream"); + } + dataLength -= readLen; + return readLen; + } + } + while (partial && loadDataLength() >= 0); + + return -1; + } + + public int read() + throws IOException + { + do + { + if (dataLength != 0) + { + int ch = in.read(); + if (ch < 0) + { + throw new EOFException("premature end of stream in PartialInputStream"); + } + dataLength--; + return ch; + } + } + while (partial && loadDataLength() >= 0); + + return -1; + } + } +} diff --git a/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java b/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java index e3b0456a..8407052b 100644 --- a/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java +++ b/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java @@ -1,46 +1,46 @@ -package org.bouncycastle.bcpg;
-
-import java.io.IOException;
-
-import org.bouncycastle.util.Arrays;
-
-/**
- * basic packet for an experimental packet.
- */
-public class ExperimentalPacket
- extends ContainedPacket implements PublicKeyAlgorithmTags
-{
- private int tag;
- private byte[] contents;
-
- /**
- *
- * @param in
- * @throws IOException
- */
- ExperimentalPacket(
- int tag,
- BCPGInputStream in)
- throws IOException
- {
- this.tag = tag;
- this.contents = in.readAll();
- }
-
- public int getTag()
- {
- return tag;
- }
-
- public byte[] getContents()
- {
- return Arrays.clone(contents);
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- out.writePacket(tag, contents, true);
- }
-}
+package org.bouncycastle.bcpg; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * basic packet for an experimental packet. + */ +public class ExperimentalPacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + private int tag; + private byte[] contents; + + /** + * + * @param in + * @throws IOException + */ + ExperimentalPacket( + int tag, + BCPGInputStream in) + throws IOException + { + this.tag = tag; + this.contents = in.readAll(); + } + + public int getTag() + { + return tag; + } + + public byte[] getContents() + { + return Arrays.clone(contents); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(tag, contents, true); + } +} diff --git a/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java b/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java index 6be9632a..d362bb93 100644 --- a/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java +++ b/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java @@ -1,185 +1,185 @@ -package org.bouncycastle.bcpg;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * basic packet for a PGP secret key
- */
-public class SecretKeyPacket
- extends ContainedPacket implements PublicKeyAlgorithmTags
-{
- public static final int USAGE_NONE = 0x00;
- public static final int USAGE_CHECKSUM = 0xff;
- public static final int USAGE_SHA1 = 0xfe;
-
- private PublicKeyPacket pubKeyPacket;
- private byte[] secKeyData;
- private int s2kUsage;
- private int encAlgorithm;
- private S2K s2k;
- private byte[] iv;
-
- /**
- *
- * @param in
- * @throws IOException
- */
- SecretKeyPacket(
- BCPGInputStream in)
- throws IOException
- {
- if (this instanceof SecretSubkeyPacket)
- {
- pubKeyPacket = new PublicSubkeyPacket(in);
- }
- else
- {
- pubKeyPacket = new PublicKeyPacket(in);
- }
-
- s2kUsage = in.read();
-
- if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1)
- {
- encAlgorithm = in.read();
- s2k = new S2K(in);
- }
- else
- {
- encAlgorithm = s2kUsage;
- }
-
- if (!(s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K && s2k.getProtectionMode() == 0x01))
- {
- if (s2kUsage != 0)
- {
- if (encAlgorithm < 7)
- {
- iv = new byte[8];
- }
- else
- {
- iv = new byte[16];
- }
- in.readFully(iv, 0, iv.length);
- }
- }
-
- this.secKeyData = in.readAll();
- }
-
- /**
- *
- * @param pubKeyPacket
- * @param encAlgorithm
- * @param s2k
- * @param iv
- * @param secKeyData
- */
- public SecretKeyPacket(
- PublicKeyPacket pubKeyPacket,
- int encAlgorithm,
- S2K s2k,
- byte[] iv,
- byte[] secKeyData)
- {
- this.pubKeyPacket = pubKeyPacket;
- this.encAlgorithm = encAlgorithm;
-
- if (encAlgorithm != SymmetricKeyAlgorithmTags.NULL)
- {
- this.s2kUsage = USAGE_CHECKSUM;
- }
- else
- {
- this.s2kUsage = USAGE_NONE;
- }
-
- this.s2k = s2k;
- this.iv = iv;
- this.secKeyData = secKeyData;
- }
-
- public SecretKeyPacket(
- PublicKeyPacket pubKeyPacket,
- int encAlgorithm,
- int s2kUsage,
- S2K s2k,
- byte[] iv,
- byte[] secKeyData)
- {
- this.pubKeyPacket = pubKeyPacket;
- this.encAlgorithm = encAlgorithm;
- this.s2kUsage = s2kUsage;
- this.s2k = s2k;
- this.iv = iv;
- this.secKeyData = secKeyData;
- }
-
- public int getEncAlgorithm()
- {
- return encAlgorithm;
- }
-
- public int getS2KUsage()
- {
- return s2kUsage;
- }
-
- public byte[] getIV()
- {
- return iv;
- }
-
- public S2K getS2K()
- {
- return s2k;
- }
-
- public PublicKeyPacket getPublicKeyPacket()
- {
- return pubKeyPacket;
- }
-
- public byte[] getSecretKeyData()
- {
- return secKeyData;
- }
-
- public byte[] getEncodedContents()
- throws IOException
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- BCPGOutputStream pOut = new BCPGOutputStream(bOut);
-
- pOut.write(pubKeyPacket.getEncodedContents());
-
- pOut.write(s2kUsage);
-
- if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1)
- {
- pOut.write(encAlgorithm);
- pOut.writeObject(s2k);
- }
-
- if (iv != null)
- {
- pOut.write(iv);
- }
-
- if (secKeyData != null && secKeyData.length > 0)
- {
- pOut.write(secKeyData);
- }
-
- return bOut.toByteArray();
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- out.writePacket(SECRET_KEY, getEncodedContents(), true);
- }
-}
+package org.bouncycastle.bcpg; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * basic packet for a PGP secret key + */ +public class SecretKeyPacket + extends ContainedPacket implements PublicKeyAlgorithmTags +{ + public static final int USAGE_NONE = 0x00; + public static final int USAGE_CHECKSUM = 0xff; + public static final int USAGE_SHA1 = 0xfe; + + private PublicKeyPacket pubKeyPacket; + private byte[] secKeyData; + private int s2kUsage; + private int encAlgorithm; + private S2K s2k; + private byte[] iv; + + /** + * + * @param in + * @throws IOException + */ + SecretKeyPacket( + BCPGInputStream in) + throws IOException + { + if (this instanceof SecretSubkeyPacket) + { + pubKeyPacket = new PublicSubkeyPacket(in); + } + else + { + pubKeyPacket = new PublicKeyPacket(in); + } + + s2kUsage = in.read(); + + if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1) + { + encAlgorithm = in.read(); + s2k = new S2K(in); + } + else + { + encAlgorithm = s2kUsage; + } + + if (!(s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K && s2k.getProtectionMode() == 0x01)) + { + if (s2kUsage != 0) + { + if (encAlgorithm < 7) + { + iv = new byte[8]; + } + else + { + iv = new byte[16]; + } + in.readFully(iv, 0, iv.length); + } + } + + this.secKeyData = in.readAll(); + } + + /** + * + * @param pubKeyPacket + * @param encAlgorithm + * @param s2k + * @param iv + * @param secKeyData + */ + public SecretKeyPacket( + PublicKeyPacket pubKeyPacket, + int encAlgorithm, + S2K s2k, + byte[] iv, + byte[] secKeyData) + { + this.pubKeyPacket = pubKeyPacket; + this.encAlgorithm = encAlgorithm; + + if (encAlgorithm != SymmetricKeyAlgorithmTags.NULL) + { + this.s2kUsage = USAGE_CHECKSUM; + } + else + { + this.s2kUsage = USAGE_NONE; + } + + this.s2k = s2k; + this.iv = iv; + this.secKeyData = secKeyData; + } + + public SecretKeyPacket( + PublicKeyPacket pubKeyPacket, + int encAlgorithm, + int s2kUsage, + S2K s2k, + byte[] iv, + byte[] secKeyData) + { + this.pubKeyPacket = pubKeyPacket; + this.encAlgorithm = encAlgorithm; + this.s2kUsage = s2kUsage; + this.s2k = s2k; + this.iv = iv; + this.secKeyData = secKeyData; + } + + public int getEncAlgorithm() + { + return encAlgorithm; + } + + public int getS2KUsage() + { + return s2kUsage; + } + + public byte[] getIV() + { + return iv; + } + + public S2K getS2K() + { + return s2k; + } + + public PublicKeyPacket getPublicKeyPacket() + { + return pubKeyPacket; + } + + public byte[] getSecretKeyData() + { + return secKeyData; + } + + public byte[] getEncodedContents() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(pubKeyPacket.getEncodedContents()); + + pOut.write(s2kUsage); + + if (s2kUsage == USAGE_CHECKSUM || s2kUsage == USAGE_SHA1) + { + pOut.write(encAlgorithm); + pOut.writeObject(s2k); + } + + if (iv != null) + { + pOut.write(iv); + } + + if (secKeyData != null && secKeyData.length > 0) + { + pOut.write(secKeyData); + } + + return bOut.toByteArray(); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(SECRET_KEY, getEncodedContents(), true); + } +} diff --git a/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java b/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java index 3e4218fe..37769fef 100644 --- a/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java +++ b/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java @@ -1,90 +1,90 @@ -package org.bouncycastle.bcpg;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-/**
- * Basic type for a symmetric encrypted session key packet
- */
-public class SymmetricKeyEncSessionPacket
- extends ContainedPacket
-{
- private int version;
- private int encAlgorithm;
- private S2K s2k;
- private byte[] secKeyData;
-
- public SymmetricKeyEncSessionPacket(
- BCPGInputStream in)
- throws IOException
- {
- version = in.read();
- encAlgorithm = in.read();
-
- s2k = new S2K(in);
-
- this.secKeyData = in.readAll();
- }
-
- public SymmetricKeyEncSessionPacket(
- int encAlgorithm,
- S2K s2k,
- byte[] secKeyData)
- {
- this.version = 4;
- this.encAlgorithm = encAlgorithm;
- this.s2k = s2k;
- this.secKeyData = secKeyData;
- }
-
- /**
- * @return int
- */
- public int getEncAlgorithm()
- {
- return encAlgorithm;
- }
-
- /**
- * @return S2K
- */
- public S2K getS2K()
- {
- return s2k;
- }
-
- /**
- * @return byte[]
- */
- public byte[] getSecKeyData()
- {
- return secKeyData;
- }
-
- /**
- * @return int
- */
- public int getVersion()
- {
- return version;
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- ByteArrayOutputStream bOut = new ByteArrayOutputStream();
- BCPGOutputStream pOut = new BCPGOutputStream(bOut);
-
- pOut.write(version);
- pOut.write(encAlgorithm);
- pOut.writeObject(s2k);
-
- if (secKeyData != null && secKeyData.length > 0)
- {
- pOut.write(secKeyData);
- }
-
- out.writePacket(SYMMETRIC_KEY_ENC_SESSION, bOut.toByteArray(), true);
- }
-}
+package org.bouncycastle.bcpg; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Basic type for a symmetric encrypted session key packet + */ +public class SymmetricKeyEncSessionPacket + extends ContainedPacket +{ + private int version; + private int encAlgorithm; + private S2K s2k; + private byte[] secKeyData; + + public SymmetricKeyEncSessionPacket( + BCPGInputStream in) + throws IOException + { + version = in.read(); + encAlgorithm = in.read(); + + s2k = new S2K(in); + + this.secKeyData = in.readAll(); + } + + public SymmetricKeyEncSessionPacket( + int encAlgorithm, + S2K s2k, + byte[] secKeyData) + { + this.version = 4; + this.encAlgorithm = encAlgorithm; + this.s2k = s2k; + this.secKeyData = secKeyData; + } + + /** + * @return int + */ + public int getEncAlgorithm() + { + return encAlgorithm; + } + + /** + * @return S2K + */ + public S2K getS2K() + { + return s2k; + } + + /** + * @return byte[] + */ + public byte[] getSecKeyData() + { + return secKeyData; + } + + /** + * @return int + */ + public int getVersion() + { + return version; + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut); + + pOut.write(version); + pOut.write(encAlgorithm); + pOut.writeObject(s2k); + + if (secKeyData != null && secKeyData.length > 0) + { + pOut.write(secKeyData); + } + + out.writePacket(SYMMETRIC_KEY_ENC_SESSION, bOut.toByteArray(), true); + } +} diff --git a/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java b/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java index dff7e5ab..15ae71b1 100644 --- a/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java +++ b/src/main/java/org/bouncycastle/bcpg/UserIDPacket.java @@ -1,39 +1,39 @@ -package org.bouncycastle.bcpg;
-
-import java.io.IOException;
-
-import org.bouncycastle.util.Strings;
-
-/**
- * Basic type for a user ID packet.
- */
-public class UserIDPacket
- extends ContainedPacket
-{
- private byte[] idData;
-
- public UserIDPacket(
- BCPGInputStream in)
- throws IOException
- {
- this.idData = in.readAll();
- }
-
- public UserIDPacket(
- String id)
- {
- this.idData = Strings.toUTF8ByteArray(id);
- }
-
- public String getID()
- {
- return Strings.fromUTF8ByteArray(idData);
- }
-
- public void encode(
- BCPGOutputStream out)
- throws IOException
- {
- out.writePacket(USER_ID, idData, true);
- }
-}
+package org.bouncycastle.bcpg; + +import java.io.IOException; + +import org.bouncycastle.util.Strings; + +/** + * Basic type for a user ID packet. + */ +public class UserIDPacket + extends ContainedPacket +{ + private byte[] idData; + + public UserIDPacket( + BCPGInputStream in) + throws IOException + { + this.idData = in.readAll(); + } + + public UserIDPacket( + String id) + { + this.idData = Strings.toUTF8ByteArray(id); + } + + public String getID() + { + return Strings.fromUTF8ByteArray(idData); + } + + public void encode( + BCPGOutputStream out) + throws IOException + { + out.writePacket(USER_ID, idData, true); + } +} diff --git a/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java b/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java index 356f8b6e..947bc5c4 100644 --- a/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java +++ b/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java @@ -1,131 +1,131 @@ -package org.bouncycastle.crypto.agreement.kdf;
-
-import java.io.IOException;
-
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.DERObjectIdentifier;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.DerivationParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.util.Pack;
-
-/**
- * RFC 2631 Diffie-hellman KEK derivation function.
- */
-public class DHKEKGenerator
- implements DerivationFunction
-{
- private final Digest digest;
-
- private DERObjectIdentifier algorithm;
- private int keySize;
- private byte[] z;
- private byte[] partyAInfo;
-
- public DHKEKGenerator(
- Digest digest)
- {
- this.digest = digest;
- }
-
- public void init(DerivationParameters param)
- {
- DHKDFParameters params = (DHKDFParameters)param;
-
- this.algorithm = params.getAlgorithm();
- this.keySize = params.getKeySize();
- this.z = params.getZ();
- this.partyAInfo = params.getExtraInfo();
- }
-
- public Digest getDigest()
- {
- return digest;
- }
-
- public int generateBytes(byte[] out, int outOff, int len)
- throws DataLengthException, IllegalArgumentException
- {
- if ((out.length - len) < outOff)
- {
- throw new DataLengthException("output buffer too small");
- }
-
- long oBytes = len;
- int outLen = digest.getDigestSize();
-
- //
- // this is at odds with the standard implementation, the
- // maximum value should be hBits * (2^32 - 1) where hBits
- // is the digest output size in bits. We can't have an
- // array with a long index at the moment...
- //
- if (oBytes > ((2L << 32) - 1))
- {
- throw new IllegalArgumentException("Output length too large");
- }
-
- int cThreshold = (int)((oBytes + outLen - 1) / outLen);
-
- byte[] dig = new byte[digest.getDigestSize()];
-
- int counter = 1;
-
- for (int i = 0; i < cThreshold; i++)
- {
- digest.update(z, 0, z.length);
-
- // OtherInfo
- ASN1EncodableVector v1 = new ASN1EncodableVector();
- // KeySpecificInfo
- ASN1EncodableVector v2 = new ASN1EncodableVector();
-
- v2.add(algorithm);
- v2.add(new DEROctetString(Pack.intToBigEndian(counter)));
-
- v1.add(new DERSequence(v2));
-
- if (partyAInfo != null)
- {
- v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo)));
- }
-
- v1.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
-
- try
- {
- byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER);
-
- digest.update(other, 0, other.length);
- }
- catch (IOException e)
- {
- throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage());
- }
-
- digest.doFinal(dig, 0);
-
- if (len > outLen)
- {
- System.arraycopy(dig, 0, out, outOff, outLen);
- outOff += outLen;
- len -= outLen;
- }
- else
- {
- System.arraycopy(dig, 0, out, outOff, len);
- }
-
- counter++;
- }
-
- digest.reset();
-
- return (int)oBytes;
- }
-}
+package org.bouncycastle.crypto.agreement.kdf; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.DerivationFunction; +import org.bouncycastle.crypto.DerivationParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.util.Pack; + +/** + * RFC 2631 Diffie-hellman KEK derivation function. + */ +public class DHKEKGenerator + implements DerivationFunction +{ + private final Digest digest; + + private DERObjectIdentifier algorithm; + private int keySize; + private byte[] z; + private byte[] partyAInfo; + + public DHKEKGenerator( + Digest digest) + { + this.digest = digest; + } + + public void init(DerivationParameters param) + { + DHKDFParameters params = (DHKDFParameters)param; + + this.algorithm = params.getAlgorithm(); + this.keySize = params.getKeySize(); + this.z = params.getZ(); + this.partyAInfo = params.getExtraInfo(); + } + + public Digest getDigest() + { + return digest; + } + + public int generateBytes(byte[] out, int outOff, int len) + throws DataLengthException, IllegalArgumentException + { + if ((out.length - len) < outOff) + { + throw new DataLengthException("output buffer too small"); + } + + long oBytes = len; + int outLen = digest.getDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + { + throw new IllegalArgumentException("Output length too large"); + } + + int cThreshold = (int)((oBytes + outLen - 1) / outLen); + + byte[] dig = new byte[digest.getDigestSize()]; + + int counter = 1; + + for (int i = 0; i < cThreshold; i++) + { + digest.update(z, 0, z.length); + + // OtherInfo + ASN1EncodableVector v1 = new ASN1EncodableVector(); + // KeySpecificInfo + ASN1EncodableVector v2 = new ASN1EncodableVector(); + + v2.add(algorithm); + v2.add(new DEROctetString(Pack.intToBigEndian(counter))); + + v1.add(new DERSequence(v2)); + + if (partyAInfo != null) + { + v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo))); + } + + v1.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize)))); + + try + { + byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER); + + digest.update(other, 0, other.length); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage()); + } + + digest.doFinal(dig, 0); + + if (len > outLen) + { + System.arraycopy(dig, 0, out, outOff, outLen); + outOff += outLen; + len -= outLen; + } + else + { + System.arraycopy(dig, 0, out, outOff, len); + } + + counter++; + } + + digest.reset(); + + return (int)oBytes; + } +} diff --git a/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java b/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java index 03ca321f..68039533 100644 --- a/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java +++ b/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java @@ -1,74 +1,74 @@ -package org.bouncycastle.crypto.agreement.kdf;
-
-import java.io.IOException;
-
-import org.bouncycastle.asn1.ASN1EncodableVector;
-import org.bouncycastle.asn1.ASN1Encoding;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.DerivationParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.crypto.util.Pack;
-
-/**
- * X9.63 based key derivation function for ECDH CMS.
- */
-public class ECDHKEKGenerator
- implements DerivationFunction
-{
- private DerivationFunction kdf;
-
- private ASN1ObjectIdentifier algorithm;
- private int keySize;
- private byte[] z;
-
- public ECDHKEKGenerator(
- Digest digest)
- {
- this.kdf = new KDF2BytesGenerator(digest);
- }
-
- public void init(DerivationParameters param)
- {
- DHKDFParameters params = (DHKDFParameters)param;
-
- this.algorithm = params.getAlgorithm();
- this.keySize = params.getKeySize();
- this.z = params.getZ();
- }
-
- public Digest getDigest()
- {
- return kdf.getDigest();
- }
-
- public int generateBytes(byte[] out, int outOff, int len)
- throws DataLengthException, IllegalArgumentException
- {
- // TODO Create an ASN.1 class for this (RFC3278)
- // ECC-CMS-SharedInfo
- ASN1EncodableVector v = new ASN1EncodableVector();
-
- v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE));
- v.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize))));
-
- try
- {
- kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER)));
- }
- catch (IOException e)
- {
- throw new IllegalArgumentException("unable to initialise kdf: " + e.getMessage());
- }
-
- return kdf.generateBytes(out, outOff, len);
- }
-}
+package org.bouncycastle.crypto.agreement.kdf; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.DerivationFunction; +import org.bouncycastle.crypto.DerivationParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import org.bouncycastle.crypto.params.KDFParameters; +import org.bouncycastle.crypto.util.Pack; + +/** + * X9.63 based key derivation function for ECDH CMS. + */ +public class ECDHKEKGenerator + implements DerivationFunction +{ + private DerivationFunction kdf; + + private ASN1ObjectIdentifier algorithm; + private int keySize; + private byte[] z; + + public ECDHKEKGenerator( + Digest digest) + { + this.kdf = new KDF2BytesGenerator(digest); + } + + public void init(DerivationParameters param) + { + DHKDFParameters params = (DHKDFParameters)param; + + this.algorithm = params.getAlgorithm(); + this.keySize = params.getKeySize(); + this.z = params.getZ(); + } + + public Digest getDigest() + { + return kdf.getDigest(); + } + + public int generateBytes(byte[] out, int outOff, int len) + throws DataLengthException, IllegalArgumentException + { + // TODO Create an ASN.1 class for this (RFC3278) + // ECC-CMS-SharedInfo + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE)); + v.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize)))); + + try + { + kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to initialise kdf: " + e.getMessage()); + } + + return kdf.generateBytes(out, outOff, len); + } +} diff --git a/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java b/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java index f77d5f56..ea8556de 100755 --- a/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java +++ b/src/main/java/org/bouncycastle/crypto/engines/IESEngine.java @@ -1,398 +1,398 @@ -package org.bouncycastle.crypto.engines;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-
-import org.bouncycastle.crypto.BasicAgreement;
-import org.bouncycastle.crypto.BufferedBlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.EphemeralKeyPair;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.KeyParser;
-import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator;
-import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.IESParameters;
-import org.bouncycastle.crypto.params.IESWithCipherParameters;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.crypto.params.KeyParameter;
-import org.bouncycastle.crypto.util.Pack;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.BigIntegers;
-
-/**
- * Support class for constructing integrated encryption ciphers
- * for doing basic message exchanges on top of key agreement ciphers.
- * Follows the description given in IEEE Std 1363a.
- */
-public class IESEngine
-{
- BasicAgreement agree;
- DerivationFunction kdf;
- Mac mac;
- BufferedBlockCipher cipher;
- byte[] macBuf;
-
- boolean forEncryption;
- CipherParameters privParam, pubParam;
- IESParameters param;
-
- byte[] V;
- private EphemeralKeyPairGenerator keyPairGenerator;
- private KeyParser keyParser;
-
-
- /**
- * set up for use with stream mode, where the key derivation function
- * is used to provide a stream of bytes to xor with the message.
- *
- * @param agree the key agreement used as the basis for the encryption
- * @param kdf the key derivation function used for byte generation
- * @param mac the message authentication code generator for the message
- */
- public IESEngine(
- BasicAgreement agree,
- DerivationFunction kdf,
- Mac mac)
- {
- this.agree = agree;
- this.kdf = kdf;
- this.mac = mac;
- this.macBuf = new byte[mac.getMacSize()];
- this.cipher = null;
- }
-
-
- /**
- * set up for use in conjunction with a block cipher to handle the
- * message.
- *
- * @param agree the key agreement used as the basis for the encryption
- * @param kdf the key derivation function used for byte generation
- * @param mac the message authentication code generator for the message
- * @param cipher the cipher to used for encrypting the message
- */
- public IESEngine(
- BasicAgreement agree,
- DerivationFunction kdf,
- Mac mac,
- BufferedBlockCipher cipher)
- {
- this.agree = agree;
- this.kdf = kdf;
- this.mac = mac;
- this.macBuf = new byte[mac.getMacSize()];
- this.cipher = cipher;
- }
-
-
- /**
- * Initialise the encryptor.
- *
- * @param forEncryption whether or not this is encryption/decryption.
- * @param privParam our private key parameters
- * @param pubParam the recipient's/sender's public key parameters
- * @param param encoding and derivation parameters.
- */
- public void init(
- boolean forEncryption,
- CipherParameters privParam,
- CipherParameters pubParam,
- CipherParameters param)
- {
- this.forEncryption = forEncryption;
- this.privParam = privParam;
- this.pubParam = pubParam;
- this.param = (IESParameters)param;
- this.V = new byte[0];
- }
-
-
- /**
- * Initialise the encryptor.
- *
- * @param publicKey the recipient's/sender's public key parameters
- * @param params encoding and derivation parameters.
- * @param ephemeralKeyPairGenerator the ephemeral key pair generator to use.
- */
- public void init(AsymmetricKeyParameter publicKey, CipherParameters params, EphemeralKeyPairGenerator ephemeralKeyPairGenerator)
- {
- this.forEncryption = true;
- this.pubParam = publicKey;
- this.param = (IESParameters)params;
- this.keyPairGenerator = ephemeralKeyPairGenerator;
- }
-
- /**
- * Initialise the encryptor.
- *
- * @param privateKey the recipient's private key.
- * @param params encoding and derivation parameters.
- * @param publicKeyParser the parser for reading the ephemeral public key.
- */
- public void init(AsymmetricKeyParameter privateKey, CipherParameters params, KeyParser publicKeyParser)
- {
- this.forEncryption = false;
- this.privParam = privateKey;
- this.param = (IESParameters)params;
- this.keyParser = publicKeyParser;
- }
-
- public BufferedBlockCipher getCipher()
- {
- return cipher;
- }
-
- public Mac getMac()
- {
- return mac;
- }
-
- private byte[] encryptBlock(
- byte[] in,
- int inOff,
- int inLen)
- throws InvalidCipherTextException
- {
- byte[] C = null, K = null, K1 = null, K2 = null;
- int len;
-
- if (cipher == null)
- {
- // Streaming mode.
- K1 = new byte[inLen];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
-
- if (V.length != 0)
- {
- System.arraycopy(K, 0, K2, 0, K2.length);
- System.arraycopy(K, K2.length, K1, 0, K1.length);
- }
- else
- {
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, inLen, K2, 0, K2.length);
- }
-
- C = new byte[inLen];
-
- for (int i = 0; i != inLen; i++)
- {
- C[i] = (byte)(in[inOff + i] ^ K1[i]);
- }
- len = inLen;
- }
- else
- {
- // Block cipher mode.
- K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, K1.length, K2, 0, K2.length);
-
- cipher.init(true, new KeyParameter(K1));
- C = new byte[cipher.getOutputSize(inLen)];
- len = cipher.processBytes(in, inOff, inLen, C, 0);
- len += cipher.doFinal(C, len);
- }
-
-
- // Convert the length of the encoding vector into a byte array.
- byte[] P2 = param.getEncodingV();
- byte[] L2 = new byte[4];
- if (V.length != 0 && P2 != null)
- {
- Pack.intToBigEndian(P2.length * 8, L2, 0);
- }
-
-
- // Apply the MAC.
- byte[] T = new byte[mac.getMacSize()];
-
- mac.init(new KeyParameter(K2));
- mac.update(C, 0, C.length);
- if (P2 != null)
- {
- mac.update(P2, 0, P2.length);
- }
- if (V.length != 0)
- {
- mac.update(L2, 0, L2.length);
- }
- mac.doFinal(T, 0);
-
-
- // Output the triple (V,C,T).
- byte[] Output = new byte[V.length + len + T.length];
- System.arraycopy(V, 0, Output, 0, V.length);
- System.arraycopy(C, 0, Output, V.length, len);
- System.arraycopy(T, 0, Output, V.length + len, T.length);
- return Output;
- }
-
- private byte[] decryptBlock(
- byte[] in_enc,
- int inOff,
- int inLen)
- throws InvalidCipherTextException
- {
- byte[] M = null, K = null, K1 = null, K2 = null;
- int len;
-
- if (cipher == null)
- {
- // Streaming mode.
- K1 = new byte[inLen - V.length - mac.getMacSize()];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
-
- if (V.length != 0)
- {
- System.arraycopy(K, 0, K2, 0, K2.length);
- System.arraycopy(K, K2.length, K1, 0, K1.length);
- }
- else
- {
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, K1.length, K2, 0, K2.length);
- }
-
- M = new byte[K1.length];
-
- for (int i = 0; i != K1.length; i++)
- {
- M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]);
- }
-
- len = K1.length;
- }
- else
- {
- // Block cipher mode.
- K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8];
- K2 = new byte[param.getMacKeySize() / 8];
- K = new byte[K1.length + K2.length];
-
- kdf.generateBytes(K, 0, K.length);
- System.arraycopy(K, 0, K1, 0, K1.length);
- System.arraycopy(K, K1.length, K2, 0, K2.length);
-
- cipher.init(false, new KeyParameter(K1));
-
- M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())];
- len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0);
- len += cipher.doFinal(M, len);
- }
-
-
- // Convert the length of the encoding vector into a byte array.
- byte[] P2 = param.getEncodingV();
- byte[] L2 = new byte[4];
- if (V.length != 0 && P2 != null)
- {
- Pack.intToBigEndian(P2.length * 8, L2, 0);
- }
-
-
- // Verify the MAC.
- int end = inOff + inLen;
- byte[] T1 = Arrays.copyOfRange(in_enc, end - mac.getMacSize(), end);
-
- byte[] T2 = new byte[T1.length];
- mac.init(new KeyParameter(K2));
- mac.update(in_enc, inOff + V.length, inLen - V.length - T2.length);
-
- if (P2 != null)
- {
- mac.update(P2, 0, P2.length);
- }
- if (V.length != 0)
- {
- mac.update(L2, 0, L2.length);
- }
- mac.doFinal(T2, 0);
-
- if (!Arrays.constantTimeAreEqual(T1, T2))
- {
- throw new InvalidCipherTextException("Invalid MAC.");
- }
-
-
- // Output the message.
- return Arrays.copyOfRange(M, 0, len);
- }
-
-
- public byte[] processBlock(
- byte[] in,
- int inOff,
- int inLen)
- throws InvalidCipherTextException
- {
- if (forEncryption)
- {
- if (keyPairGenerator != null)
- {
- EphemeralKeyPair ephKeyPair = keyPairGenerator.generate();
-
- this.privParam = ephKeyPair.getKeyPair().getPrivate();
- this.V = ephKeyPair.getEncodedPublicKey();
- }
- }
- else
- {
- if (keyParser != null)
- {
- ByteArrayInputStream bIn = new ByteArrayInputStream(in, inOff, inLen);
-
- try
- {
- this.pubParam = keyParser.readKey(bIn);
- }
- catch (IOException e)
- {
- throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e);
- }
-
- int encLength = (inLen - bIn.available());
- this.V = Arrays.copyOfRange(in, inOff, inOff + encLength);
- }
- }
-
- // Compute the common value and convert to byte array.
- agree.init(privParam);
- BigInteger z = agree.calculateAgreement(pubParam);
- byte[] Z = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), z);
-
- // Create input to KDF.
- byte[] VZ;
- if (V.length != 0)
- {
- VZ = new byte[V.length + Z.length];
- System.arraycopy(V, 0, VZ, 0, V.length);
- System.arraycopy(Z, 0, VZ, V.length, Z.length);
- }
- else
- {
- VZ = Z;
- }
-
- // Initialise the KDF.
- KDFParameters kdfParam = new KDFParameters(VZ, param.getDerivationV());
- kdf.init(kdfParam);
-
- return forEncryption
- ? encryptBlock(in, inOff, inLen)
- : decryptBlock(in, inOff, inLen);
- }
-}
+package org.bouncycastle.crypto.engines; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.crypto.BasicAgreement; +import org.bouncycastle.crypto.BufferedBlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DerivationFunction; +import org.bouncycastle.crypto.EphemeralKeyPair; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.KeyParser; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.IESParameters; +import org.bouncycastle.crypto.params.IESWithCipherParameters; +import org.bouncycastle.crypto.params.KDFParameters; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +/** + * Support class for constructing integrated encryption ciphers + * for doing basic message exchanges on top of key agreement ciphers. + * Follows the description given in IEEE Std 1363a. + */ +public class IESEngine +{ + BasicAgreement agree; + DerivationFunction kdf; + Mac mac; + BufferedBlockCipher cipher; + byte[] macBuf; + + boolean forEncryption; + CipherParameters privParam, pubParam; + IESParameters param; + + byte[] V; + private EphemeralKeyPairGenerator keyPairGenerator; + private KeyParser keyParser; + + + /** + * set up for use with stream mode, where the key derivation function + * is used to provide a stream of bytes to xor with the message. + * + * @param agree the key agreement used as the basis for the encryption + * @param kdf the key derivation function used for byte generation + * @param mac the message authentication code generator for the message + */ + public IESEngine( + BasicAgreement agree, + DerivationFunction kdf, + Mac mac) + { + this.agree = agree; + this.kdf = kdf; + this.mac = mac; + this.macBuf = new byte[mac.getMacSize()]; + this.cipher = null; + } + + + /** + * set up for use in conjunction with a block cipher to handle the + * message. + * + * @param agree the key agreement used as the basis for the encryption + * @param kdf the key derivation function used for byte generation + * @param mac the message authentication code generator for the message + * @param cipher the cipher to used for encrypting the message + */ + public IESEngine( + BasicAgreement agree, + DerivationFunction kdf, + Mac mac, + BufferedBlockCipher cipher) + { + this.agree = agree; + this.kdf = kdf; + this.mac = mac; + this.macBuf = new byte[mac.getMacSize()]; + this.cipher = cipher; + } + + + /** + * Initialise the encryptor. + * + * @param forEncryption whether or not this is encryption/decryption. + * @param privParam our private key parameters + * @param pubParam the recipient's/sender's public key parameters + * @param param encoding and derivation parameters. + */ + public void init( + boolean forEncryption, + CipherParameters privParam, + CipherParameters pubParam, + CipherParameters param) + { + this.forEncryption = forEncryption; + this.privParam = privParam; + this.pubParam = pubParam; + this.param = (IESParameters)param; + this.V = new byte[0]; + } + + + /** + * Initialise the encryptor. + * + * @param publicKey the recipient's/sender's public key parameters + * @param params encoding and derivation parameters. + * @param ephemeralKeyPairGenerator the ephemeral key pair generator to use. + */ + public void init(AsymmetricKeyParameter publicKey, CipherParameters params, EphemeralKeyPairGenerator ephemeralKeyPairGenerator) + { + this.forEncryption = true; + this.pubParam = publicKey; + this.param = (IESParameters)params; + this.keyPairGenerator = ephemeralKeyPairGenerator; + } + + /** + * Initialise the encryptor. + * + * @param privateKey the recipient's private key. + * @param params encoding and derivation parameters. + * @param publicKeyParser the parser for reading the ephemeral public key. + */ + public void init(AsymmetricKeyParameter privateKey, CipherParameters params, KeyParser publicKeyParser) + { + this.forEncryption = false; + this.privParam = privateKey; + this.param = (IESParameters)params; + this.keyParser = publicKeyParser; + } + + public BufferedBlockCipher getCipher() + { + return cipher; + } + + public Mac getMac() + { + return mac; + } + + private byte[] encryptBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] C = null, K = null, K1 = null, K2 = null; + int len; + + if (cipher == null) + { + // Streaming mode. + K1 = new byte[inLen]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + + if (V.length != 0) + { + System.arraycopy(K, 0, K2, 0, K2.length); + System.arraycopy(K, K2.length, K1, 0, K1.length); + } + else + { + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, inLen, K2, 0, K2.length); + } + + C = new byte[inLen]; + + for (int i = 0; i != inLen; i++) + { + C[i] = (byte)(in[inOff + i] ^ K1[i]); + } + len = inLen; + } + else + { + // Block cipher mode. + K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, K1.length, K2, 0, K2.length); + + cipher.init(true, new KeyParameter(K1)); + C = new byte[cipher.getOutputSize(inLen)]; + len = cipher.processBytes(in, inOff, inLen, C, 0); + len += cipher.doFinal(C, len); + } + + + // Convert the length of the encoding vector into a byte array. + byte[] P2 = param.getEncodingV(); + byte[] L2 = new byte[4]; + if (V.length != 0 && P2 != null) + { + Pack.intToBigEndian(P2.length * 8, L2, 0); + } + + + // Apply the MAC. + byte[] T = new byte[mac.getMacSize()]; + + mac.init(new KeyParameter(K2)); + mac.update(C, 0, C.length); + if (P2 != null) + { + mac.update(P2, 0, P2.length); + } + if (V.length != 0) + { + mac.update(L2, 0, L2.length); + } + mac.doFinal(T, 0); + + + // Output the triple (V,C,T). + byte[] Output = new byte[V.length + len + T.length]; + System.arraycopy(V, 0, Output, 0, V.length); + System.arraycopy(C, 0, Output, V.length, len); + System.arraycopy(T, 0, Output, V.length + len, T.length); + return Output; + } + + private byte[] decryptBlock( + byte[] in_enc, + int inOff, + int inLen) + throws InvalidCipherTextException + { + byte[] M = null, K = null, K1 = null, K2 = null; + int len; + + if (cipher == null) + { + // Streaming mode. + K1 = new byte[inLen - V.length - mac.getMacSize()]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + + if (V.length != 0) + { + System.arraycopy(K, 0, K2, 0, K2.length); + System.arraycopy(K, K2.length, K1, 0, K1.length); + } + else + { + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, K1.length, K2, 0, K2.length); + } + + M = new byte[K1.length]; + + for (int i = 0; i != K1.length; i++) + { + M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]); + } + + len = K1.length; + } + else + { + // Block cipher mode. + K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, K1.length, K2, 0, K2.length); + + cipher.init(false, new KeyParameter(K1)); + + M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())]; + len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0); + len += cipher.doFinal(M, len); + } + + + // Convert the length of the encoding vector into a byte array. + byte[] P2 = param.getEncodingV(); + byte[] L2 = new byte[4]; + if (V.length != 0 && P2 != null) + { + Pack.intToBigEndian(P2.length * 8, L2, 0); + } + + + // Verify the MAC. + int end = inOff + inLen; + byte[] T1 = Arrays.copyOfRange(in_enc, end - mac.getMacSize(), end); + + byte[] T2 = new byte[T1.length]; + mac.init(new KeyParameter(K2)); + mac.update(in_enc, inOff + V.length, inLen - V.length - T2.length); + + if (P2 != null) + { + mac.update(P2, 0, P2.length); + } + if (V.length != 0) + { + mac.update(L2, 0, L2.length); + } + mac.doFinal(T2, 0); + + if (!Arrays.constantTimeAreEqual(T1, T2)) + { + throw new InvalidCipherTextException("Invalid MAC."); + } + + + // Output the message. + return Arrays.copyOfRange(M, 0, len); + } + + + public byte[] processBlock( + byte[] in, + int inOff, + int inLen) + throws InvalidCipherTextException + { + if (forEncryption) + { + if (keyPairGenerator != null) + { + EphemeralKeyPair ephKeyPair = keyPairGenerator.generate(); + + this.privParam = ephKeyPair.getKeyPair().getPrivate(); + this.V = ephKeyPair.getEncodedPublicKey(); + } + } + else + { + if (keyParser != null) + { + ByteArrayInputStream bIn = new ByteArrayInputStream(in, inOff, inLen); + + try + { + this.pubParam = keyParser.readKey(bIn); + } + catch (IOException e) + { + throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e); + } + + int encLength = (inLen - bIn.available()); + this.V = Arrays.copyOfRange(in, inOff, inOff + encLength); + } + } + + // Compute the common value and convert to byte array. + agree.init(privParam); + BigInteger z = agree.calculateAgreement(pubParam); + byte[] Z = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), z); + + // Create input to KDF. + byte[] VZ; + if (V.length != 0) + { + VZ = new byte[V.length + Z.length]; + System.arraycopy(V, 0, VZ, 0, V.length); + System.arraycopy(Z, 0, VZ, V.length, Z.length); + } + else + { + VZ = Z; + } + + // Initialise the KDF. + KDFParameters kdfParam = new KDFParameters(VZ, param.getDerivationV()); + kdf.init(kdfParam); + + return forEncryption + ? encryptBlock(in, inOff, inLen) + : decryptBlock(in, inOff, inLen); + } +} diff --git a/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java b/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java index c6e39986..2ef8dd2b 100644 --- a/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java +++ b/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java @@ -1,142 +1,142 @@ -package org.bouncycastle.crypto.generators;
-
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.DerivationParameters;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.params.ISO18033KDFParameters;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.crypto.util.Pack;
-
-/**
- * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO
- * 18033 <br>
- * This implementation is based on ISO 18033/P1363a.
- */
-public class BaseKDFBytesGenerator implements DerivationFunction
-{
- private int counterStart;
- private Digest digest;
- private byte[] shared;
- private byte[] iv;
-
- /**
- * Construct a KDF Parameters generator.
- * <p>
- *
- * @param counterStart
- * value of counter.
- * @param digest
- * the digest to be used as the source of derived keys.
- */
- protected BaseKDFBytesGenerator(int counterStart, Digest digest)
- {
- this.counterStart = counterStart;
- this.digest = digest;
- }
-
- public void init(DerivationParameters param)
- {
- if (param instanceof KDFParameters)
- {
- KDFParameters p = (KDFParameters)param;
-
- shared = p.getSharedSecret();
- iv = p.getIV();
- }
- else if (param instanceof ISO18033KDFParameters)
- {
- ISO18033KDFParameters p = (ISO18033KDFParameters)param;
-
- shared = p.getSeed();
- iv = null;
- }
- else
- {
- throw new IllegalArgumentException("KDF parameters required for KDF2Generator");
- }
- }
-
- /**
- * return the underlying digest.
- */
- public Digest getDigest()
- {
- return digest;
- }
-
- /**
- * fill len bytes of the output buffer with bytes generated from the
- * derivation function.
- *
- * @throws IllegalArgumentException
- * if the size of the request will cause an overflow.
- * @throws DataLengthException
- * if the out buffer is too small.
- */
- public int generateBytes(byte[] out, int outOff, int len) throws DataLengthException,
- IllegalArgumentException
- {
- if ((out.length - len) < outOff)
- {
- throw new DataLengthException("output buffer too small");
- }
-
- long oBytes = len;
- int outLen = digest.getDigestSize();
-
- //
- // this is at odds with the standard implementation, the
- // maximum value should be hBits * (2^32 - 1) where hBits
- // is the digest output size in bits. We can't have an
- // array with a long index at the moment...
- //
- if (oBytes > ((2L << 32) - 1))
- {
- throw new IllegalArgumentException("Output length too large");
- }
-
- int cThreshold = (int)((oBytes + outLen - 1) / outLen);
-
- byte[] dig = new byte[digest.getDigestSize()];
-
- byte[] C = new byte[4];
- Pack.intToBigEndian(counterStart, C, 0);
-
- int counterBase = counterStart & ~0xFF;
-
- for (int i = 0; i < cThreshold; i++)
- {
- digest.update(shared, 0, shared.length);
- digest.update(C, 0, C.length);
-
- if (iv != null)
- {
- digest.update(iv, 0, iv.length);
- }
-
- digest.doFinal(dig, 0);
-
- if (len > outLen)
- {
- System.arraycopy(dig, 0, out, outOff, outLen);
- outOff += outLen;
- len -= outLen;
- }
- else
- {
- System.arraycopy(dig, 0, out, outOff, len);
- }
-
- if (++C[3] == 0)
- {
- counterBase += 0x100;
- Pack.intToBigEndian(counterBase, C, 0);
- }
- }
-
- digest.reset();
-
- return (int)oBytes;
- }
-}
+package org.bouncycastle.crypto.generators; + +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.DerivationFunction; +import org.bouncycastle.crypto.DerivationParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.params.ISO18033KDFParameters; +import org.bouncycastle.crypto.params.KDFParameters; +import org.bouncycastle.crypto.util.Pack; + +/** + * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO + * 18033 <br> + * This implementation is based on ISO 18033/P1363a. + */ +public class BaseKDFBytesGenerator implements DerivationFunction +{ + private int counterStart; + private Digest digest; + private byte[] shared; + private byte[] iv; + + /** + * Construct a KDF Parameters generator. + * <p> + * + * @param counterStart + * value of counter. + * @param digest + * the digest to be used as the source of derived keys. + */ + protected BaseKDFBytesGenerator(int counterStart, Digest digest) + { + this.counterStart = counterStart; + this.digest = digest; + } + + public void init(DerivationParameters param) + { + if (param instanceof KDFParameters) + { + KDFParameters p = (KDFParameters)param; + + shared = p.getSharedSecret(); + iv = p.getIV(); + } + else if (param instanceof ISO18033KDFParameters) + { + ISO18033KDFParameters p = (ISO18033KDFParameters)param; + + shared = p.getSeed(); + iv = null; + } + else + { + throw new IllegalArgumentException("KDF parameters required for KDF2Generator"); + } + } + + /** + * return the underlying digest. + */ + public Digest getDigest() + { + return digest; + } + + /** + * fill len bytes of the output buffer with bytes generated from the + * derivation function. + * + * @throws IllegalArgumentException + * if the size of the request will cause an overflow. + * @throws DataLengthException + * if the out buffer is too small. + */ + public int generateBytes(byte[] out, int outOff, int len) throws DataLengthException, + IllegalArgumentException + { + if ((out.length - len) < outOff) + { + throw new DataLengthException("output buffer too small"); + } + + long oBytes = len; + int outLen = digest.getDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + { + throw new IllegalArgumentException("Output length too large"); + } + + int cThreshold = (int)((oBytes + outLen - 1) / outLen); + + byte[] dig = new byte[digest.getDigestSize()]; + + byte[] C = new byte[4]; + Pack.intToBigEndian(counterStart, C, 0); + + int counterBase = counterStart & ~0xFF; + + for (int i = 0; i < cThreshold; i++) + { + digest.update(shared, 0, shared.length); + digest.update(C, 0, C.length); + + if (iv != null) + { + digest.update(iv, 0, iv.length); + } + + digest.doFinal(dig, 0); + + if (len > outLen) + { + System.arraycopy(dig, 0, out, outOff, outLen); + outOff += outLen; + len -= outLen; + } + else + { + System.arraycopy(dig, 0, out, outOff, len); + } + + if (++C[3] == 0) + { + counterBase += 0x100; + Pack.intToBigEndian(counterBase, C, 0); + } + } + + digest.reset(); + + return (int)oBytes; + } +} diff --git a/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java index 600dd297..9a6e2e0c 100644 --- a/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -1,378 +1,378 @@ -package org.bouncycastle.crypto.modes;
-
-import java.io.ByteArrayOutputStream;
-
-import org.bouncycastle.crypto.BlockCipher;
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DataLengthException;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.Mac;
-import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
-import org.bouncycastle.crypto.params.AEADParameters;
-import org.bouncycastle.crypto.params.ParametersWithIV;
-import org.bouncycastle.util.Arrays;
-
-/**
- * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
- * NIST Special Publication 800-38C.
- * <p>
- * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
- */
-public class CCMBlockCipher
- implements AEADBlockCipher
-{
- private BlockCipher cipher;
- private int blockSize;
- private boolean forEncryption;
- private byte[] nonce;
- private byte[] initialAssociatedText;
- private int macSize;
- private CipherParameters keyParam;
- private byte[] macBlock;
- private ByteArrayOutputStream associatedText = new ByteArrayOutputStream();
- private ByteArrayOutputStream data = new ByteArrayOutputStream();
-
- /**
- * Basic constructor.
- *
- * @param c the block cipher to be used.
- */
- public CCMBlockCipher(BlockCipher c)
- {
- this.cipher = c;
- this.blockSize = c.getBlockSize();
- this.macBlock = new byte[blockSize];
-
- if (blockSize != 16)
- {
- throw new IllegalArgumentException("cipher required with a block size of 16.");
- }
- }
-
- /**
- * return the underlying block cipher that we are wrapping.
- *
- * @return the underlying block cipher that we are wrapping.
- */
- public BlockCipher getUnderlyingCipher()
- {
- return cipher;
- }
-
-
- public void init(boolean forEncryption, CipherParameters params)
- throws IllegalArgumentException
- {
- this.forEncryption = forEncryption;
-
- if (params instanceof AEADParameters)
- {
- AEADParameters param = (AEADParameters)params;
-
- nonce = param.getNonce();
- initialAssociatedText = param.getAssociatedText();
- macSize = param.getMacSize() / 8;
- keyParam = param.getKey();
- }
- else if (params instanceof ParametersWithIV)
- {
- ParametersWithIV param = (ParametersWithIV)params;
-
- nonce = param.getIV();
- initialAssociatedText = null;
- macSize = macBlock.length / 2;
- keyParam = param.getParameters();
- }
- else
- {
- throw new IllegalArgumentException("invalid parameters passed to CCM");
- }
-
- if (nonce == null || nonce.length < 7 || nonce.length > 13)
- {
- throw new IllegalArgumentException("nonce must have length from 7 to 13 octets");
- }
- }
-
- public String getAlgorithmName()
- {
- return cipher.getAlgorithmName() + "/CCM";
- }
-
- public void processAADByte(byte in)
- {
- associatedText.write(in);
- }
-
- public void processAADBytes(byte[] in, int inOff, int len)
- {
- // TODO: Process AAD online
- associatedText.write(in, inOff, len);
- }
-
- public int processByte(byte in, byte[] out, int outOff)
- throws DataLengthException, IllegalStateException
- {
- data.write(in);
-
- return 0;
- }
-
- public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
- throws DataLengthException, IllegalStateException
- {
- data.write(in, inOff, inLen);
-
- return 0;
- }
-
- public int doFinal(byte[] out, int outOff)
- throws IllegalStateException, InvalidCipherTextException
- {
- byte[] text = data.toByteArray();
- byte[] enc = processPacket(text, 0, text.length);
-
- System.arraycopy(enc, 0, out, outOff, enc.length);
-
- reset();
-
- return enc.length;
- }
-
- public void reset()
- {
- cipher.reset();
- associatedText.reset();
- data.reset();
- }
-
- /**
- * Returns a byte array containing the mac calculated as part of the
- * last encrypt or decrypt operation.
- *
- * @return the last mac calculated.
- */
- public byte[] getMac()
- {
- byte[] mac = new byte[macSize];
-
- System.arraycopy(macBlock, 0, mac, 0, mac.length);
-
- return mac;
- }
-
- public int getUpdateOutputSize(int len)
- {
- return 0;
- }
-
- public int getOutputSize(int len)
- {
- int totalData = len + data.size();
-
- if (forEncryption)
- {
- return totalData + macSize;
- }
-
- return totalData < macSize ? 0 : totalData - macSize;
- }
-
- public byte[] processPacket(byte[] in, int inOff, int inLen)
- throws IllegalStateException, InvalidCipherTextException
- {
- // TODO: handle null keyParam (e.g. via RepeatedKeySpec)
- // Need to keep the CTR and CBC Mac parts around and reset
- if (keyParam == null)
- {
- throw new IllegalStateException("CCM cipher unitialized.");
- }
-
- int n = nonce.length;
- int q = 15 - n;
- if (q < 4)
- {
- int limitLen = 1 << (8 * q);
- if (inLen >= limitLen)
- {
- throw new IllegalStateException("CCM packet too large for choice of q.");
- }
- }
-
- byte[] iv = new byte[blockSize];
- iv[0] = (byte)((q - 1) & 0x7);
- System.arraycopy(nonce, 0, iv, 1, nonce.length);
-
- BlockCipher ctrCipher = new SICBlockCipher(cipher);
- ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
-
- int index = inOff;
- int outOff = 0;
- byte[] output;
-
- if (forEncryption)
- {
- output = new byte[inLen + macSize];
-
- calculateMac(in, inOff, inLen, macBlock);
-
- ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0
-
- while (index < inLen - blockSize) // S1...
- {
- ctrCipher.processBlock(in, index, output, outOff);
- outOff += blockSize;
- index += blockSize;
- }
-
- byte[] block = new byte[blockSize];
-
- System.arraycopy(in, index, block, 0, inLen - index);
-
- ctrCipher.processBlock(block, 0, block, 0);
-
- System.arraycopy(block, 0, output, outOff, inLen - index);
-
- outOff += inLen - index;
-
- System.arraycopy(macBlock, 0, output, outOff, output.length - outOff);
- }
- else
- {
- output = new byte[inLen - macSize];
-
- System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
-
- ctrCipher.processBlock(macBlock, 0, macBlock, 0);
-
- for (int i = macSize; i != macBlock.length; i++)
- {
- macBlock[i] = 0;
- }
-
- while (outOff < output.length - blockSize)
- {
- ctrCipher.processBlock(in, index, output, outOff);
- outOff += blockSize;
- index += blockSize;
- }
-
- byte[] block = new byte[blockSize];
-
- System.arraycopy(in, index, block, 0, output.length - outOff);
-
- ctrCipher.processBlock(block, 0, block, 0);
-
- System.arraycopy(block, 0, output, outOff, output.length - outOff);
-
- byte[] calculatedMacBlock = new byte[blockSize];
-
- calculateMac(output, 0, output.length, calculatedMacBlock);
-
- if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
- {
- throw new InvalidCipherTextException("mac check in CCM failed");
- }
- }
-
- return output;
- }
-
- private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
- {
- Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8);
-
- cMac.init(keyParam);
-
- //
- // build b0
- //
- byte[] b0 = new byte[16];
-
- if (hasAssociatedText())
- {
- b0[0] |= 0x40;
- }
-
- b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3;
-
- b0[0] |= ((15 - nonce.length) - 1) & 0x7;
-
- System.arraycopy(nonce, 0, b0, 1, nonce.length);
-
- int q = dataLen;
- int count = 1;
- while (q > 0)
- {
- b0[b0.length - count] = (byte)(q & 0xff);
- q >>>= 8;
- count++;
- }
-
- cMac.update(b0, 0, b0.length);
-
- //
- // process associated text
- //
- if (hasAssociatedText())
- {
- int extra;
-
- int textLength = getAssociatedTextLength();
- if (textLength < ((1 << 16) - (1 << 8)))
- {
- cMac.update((byte)(textLength >> 8));
- cMac.update((byte)textLength);
-
- extra = 2;
- }
- else // can't go any higher than 2^32
- {
- cMac.update((byte)0xff);
- cMac.update((byte)0xfe);
- cMac.update((byte)(textLength >> 24));
- cMac.update((byte)(textLength >> 16));
- cMac.update((byte)(textLength >> 8));
- cMac.update((byte)textLength);
-
- extra = 6;
- }
-
- if (initialAssociatedText != null)
- {
- cMac.update(initialAssociatedText, 0, initialAssociatedText.length);
- }
- if (associatedText.size() > 0)
- {
- byte[] tmp = associatedText.toByteArray();
- cMac.update(tmp, 0, tmp.length);
- }
-
- extra = (extra + textLength) % 16;
- if (extra != 0)
- {
- for (int i = extra; i != 16; i++)
- {
- cMac.update((byte)0x00);
- }
- }
- }
-
- //
- // add the text
- //
- cMac.update(data, dataOff, dataLen);
-
- return cMac.doFinal(macBlock, 0);
- }
-
- private int getAssociatedTextLength()
- {
- return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length);
- }
-
- private boolean hasAssociatedText()
- {
- return getAssociatedTextLength() > 0;
- }
-}
+package org.bouncycastle.crypto.modes; + +import java.io.ByteArrayOutputStream; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.macs.CBCBlockCipherMac; +import org.bouncycastle.crypto.params.AEADParameters; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; + +/** + * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in + * NIST Special Publication 800-38C. + * <p> + * <b>Note</b>: this mode is a packet mode - it needs all the data up front. + */ +public class CCMBlockCipher + implements AEADBlockCipher +{ + private BlockCipher cipher; + private int blockSize; + private boolean forEncryption; + private byte[] nonce; + private byte[] initialAssociatedText; + private int macSize; + private CipherParameters keyParam; + private byte[] macBlock; + private ByteArrayOutputStream associatedText = new ByteArrayOutputStream(); + private ByteArrayOutputStream data = new ByteArrayOutputStream(); + + /** + * Basic constructor. + * + * @param c the block cipher to be used. + */ + public CCMBlockCipher(BlockCipher c) + { + this.cipher = c; + this.blockSize = c.getBlockSize(); + this.macBlock = new byte[blockSize]; + + if (blockSize != 16) + { + throw new IllegalArgumentException("cipher required with a block size of 16."); + } + } + + /** + * return the underlying block cipher that we are wrapping. + * + * @return the underlying block cipher that we are wrapping. + */ + public BlockCipher getUnderlyingCipher() + { + return cipher; + } + + + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + this.forEncryption = forEncryption; + + if (params instanceof AEADParameters) + { + AEADParameters param = (AEADParameters)params; + + nonce = param.getNonce(); + initialAssociatedText = param.getAssociatedText(); + macSize = param.getMacSize() / 8; + keyParam = param.getKey(); + } + else if (params instanceof ParametersWithIV) + { + ParametersWithIV param = (ParametersWithIV)params; + + nonce = param.getIV(); + initialAssociatedText = null; + macSize = macBlock.length / 2; + keyParam = param.getParameters(); + } + else + { + throw new IllegalArgumentException("invalid parameters passed to CCM"); + } + + if (nonce == null || nonce.length < 7 || nonce.length > 13) + { + throw new IllegalArgumentException("nonce must have length from 7 to 13 octets"); + } + } + + public String getAlgorithmName() + { + return cipher.getAlgorithmName() + "/CCM"; + } + + public void processAADByte(byte in) + { + associatedText.write(in); + } + + public void processAADBytes(byte[] in, int inOff, int len) + { + // TODO: Process AAD online + associatedText.write(in, inOff, len); + } + + public int processByte(byte in, byte[] out, int outOff) + throws DataLengthException, IllegalStateException + { + data.write(in); + + return 0; + } + + public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff) + throws DataLengthException, IllegalStateException + { + data.write(in, inOff, inLen); + + return 0; + } + + public int doFinal(byte[] out, int outOff) + throws IllegalStateException, InvalidCipherTextException + { + byte[] text = data.toByteArray(); + byte[] enc = processPacket(text, 0, text.length); + + System.arraycopy(enc, 0, out, outOff, enc.length); + + reset(); + + return enc.length; + } + + public void reset() + { + cipher.reset(); + associatedText.reset(); + data.reset(); + } + + /** + * Returns a byte array containing the mac calculated as part of the + * last encrypt or decrypt operation. + * + * @return the last mac calculated. + */ + public byte[] getMac() + { + byte[] mac = new byte[macSize]; + + System.arraycopy(macBlock, 0, mac, 0, mac.length); + + return mac; + } + + public int getUpdateOutputSize(int len) + { + return 0; + } + + public int getOutputSize(int len) + { + int totalData = len + data.size(); + + if (forEncryption) + { + return totalData + macSize; + } + + return totalData < macSize ? 0 : totalData - macSize; + } + + public byte[] processPacket(byte[] in, int inOff, int inLen) + throws IllegalStateException, InvalidCipherTextException + { + // TODO: handle null keyParam (e.g. via RepeatedKeySpec) + // Need to keep the CTR and CBC Mac parts around and reset + if (keyParam == null) + { + throw new IllegalStateException("CCM cipher unitialized."); + } + + int n = nonce.length; + int q = 15 - n; + if (q < 4) + { + int limitLen = 1 << (8 * q); + if (inLen >= limitLen) + { + throw new IllegalStateException("CCM packet too large for choice of q."); + } + } + + byte[] iv = new byte[blockSize]; + iv[0] = (byte)((q - 1) & 0x7); + System.arraycopy(nonce, 0, iv, 1, nonce.length); + + BlockCipher ctrCipher = new SICBlockCipher(cipher); + ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv)); + + int index = inOff; + int outOff = 0; + byte[] output; + + if (forEncryption) + { + output = new byte[inLen + macSize]; + + calculateMac(in, inOff, inLen, macBlock); + + ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0 + + while (index < inLen - blockSize) // S1... + { + ctrCipher.processBlock(in, index, output, outOff); + outOff += blockSize; + index += blockSize; + } + + byte[] block = new byte[blockSize]; + + System.arraycopy(in, index, block, 0, inLen - index); + + ctrCipher.processBlock(block, 0, block, 0); + + System.arraycopy(block, 0, output, outOff, inLen - index); + + outOff += inLen - index; + + System.arraycopy(macBlock, 0, output, outOff, output.length - outOff); + } + else + { + output = new byte[inLen - macSize]; + + System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize); + + ctrCipher.processBlock(macBlock, 0, macBlock, 0); + + for (int i = macSize; i != macBlock.length; i++) + { + macBlock[i] = 0; + } + + while (outOff < output.length - blockSize) + { + ctrCipher.processBlock(in, index, output, outOff); + outOff += blockSize; + index += blockSize; + } + + byte[] block = new byte[blockSize]; + + System.arraycopy(in, index, block, 0, output.length - outOff); + + ctrCipher.processBlock(block, 0, block, 0); + + System.arraycopy(block, 0, output, outOff, output.length - outOff); + + byte[] calculatedMacBlock = new byte[blockSize]; + + calculateMac(output, 0, output.length, calculatedMacBlock); + + if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock)) + { + throw new InvalidCipherTextException("mac check in CCM failed"); + } + } + + return output; + } + + private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock) + { + Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8); + + cMac.init(keyParam); + + // + // build b0 + // + byte[] b0 = new byte[16]; + + if (hasAssociatedText()) + { + b0[0] |= 0x40; + } + + b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3; + + b0[0] |= ((15 - nonce.length) - 1) & 0x7; + + System.arraycopy(nonce, 0, b0, 1, nonce.length); + + int q = dataLen; + int count = 1; + while (q > 0) + { + b0[b0.length - count] = (byte)(q & 0xff); + q >>>= 8; + count++; + } + + cMac.update(b0, 0, b0.length); + + // + // process associated text + // + if (hasAssociatedText()) + { + int extra; + + int textLength = getAssociatedTextLength(); + if (textLength < ((1 << 16) - (1 << 8))) + { + cMac.update((byte)(textLength >> 8)); + cMac.update((byte)textLength); + + extra = 2; + } + else // can't go any higher than 2^32 + { + cMac.update((byte)0xff); + cMac.update((byte)0xfe); + cMac.update((byte)(textLength >> 24)); + cMac.update((byte)(textLength >> 16)); + cMac.update((byte)(textLength >> 8)); + cMac.update((byte)textLength); + + extra = 6; + } + + if (initialAssociatedText != null) + { + cMac.update(initialAssociatedText, 0, initialAssociatedText.length); + } + if (associatedText.size() > 0) + { + byte[] tmp = associatedText.toByteArray(); + cMac.update(tmp, 0, tmp.length); + } + + extra = (extra + textLength) % 16; + if (extra != 0) + { + for (int i = extra; i != 16; i++) + { + cMac.update((byte)0x00); + } + } + } + + // + // add the text + // + cMac.update(data, dataOff, dataLen); + + return cMac.doFinal(macBlock, 0); + } + + private int getAssociatedTextLength() + { + return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length); + } + + private boolean hasAssociatedText() + { + return getAssociatedTextLength() > 0; + } +} diff --git a/src/main/java/org/bouncycastle/crypto/util/Pack.java b/src/main/java/org/bouncycastle/crypto/util/Pack.java index b767cc9e..d2ce166b 100644 --- a/src/main/java/org/bouncycastle/crypto/util/Pack.java +++ b/src/main/java/org/bouncycastle/crypto/util/Pack.java @@ -1,192 +1,192 @@ -package org.bouncycastle.crypto.util;
-
-public abstract class Pack
-{
- public static int bigEndianToInt(byte[] bs, int off)
- {
- int n = bs[ off] << 24;
- n |= (bs[++off] & 0xff) << 16;
- n |= (bs[++off] & 0xff) << 8;
- n |= (bs[++off] & 0xff);
- return n;
- }
-
- public static void bigEndianToInt(byte[] bs, int off, int[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = bigEndianToInt(bs, off);
- off += 4;
- }
- }
-
- public static byte[] intToBigEndian(int n)
- {
- byte[] bs = new byte[4];
- intToBigEndian(n, bs, 0);
- return bs;
- }
-
- public static void intToBigEndian(int n, byte[] bs, int off)
- {
- bs[ off] = (byte)(n >>> 24);
- bs[++off] = (byte)(n >>> 16);
- bs[++off] = (byte)(n >>> 8);
- bs[++off] = (byte)(n );
- }
-
- public static byte[] intToBigEndian(int[] ns)
- {
- byte[] bs = new byte[4 * ns.length];
- intToBigEndian(ns, bs, 0);
- return bs;
- }
-
- public static void intToBigEndian(int[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- intToBigEndian(ns[i], bs, off);
- off += 4;
- }
- }
-
- public static long bigEndianToLong(byte[] bs, int off)
- {
- int hi = bigEndianToInt(bs, off);
- int lo = bigEndianToInt(bs, off + 4);
- return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
- }
-
- public static void bigEndianToLong(byte[] bs, int off, long[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = bigEndianToLong(bs, off);
- off += 8;
- }
- }
-
- public static byte[] longToBigEndian(long n)
- {
- byte[] bs = new byte[8];
- longToBigEndian(n, bs, 0);
- return bs;
- }
-
- public static void longToBigEndian(long n, byte[] bs, int off)
- {
- intToBigEndian((int)(n >>> 32), bs, off);
- intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
- }
-
- public static byte[] longToBigEndian(long[] ns)
- {
- byte[] bs = new byte[8 * ns.length];
- longToBigEndian(ns, bs, 0);
- return bs;
- }
-
- public static void longToBigEndian(long[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- longToBigEndian(ns[i], bs, off);
- off += 8;
- }
- }
-
- public static int littleEndianToInt(byte[] bs, int off)
- {
- int n = bs[ off] & 0xff;
- n |= (bs[++off] & 0xff) << 8;
- n |= (bs[++off] & 0xff) << 16;
- n |= bs[++off] << 24;
- return n;
- }
-
- public static void littleEndianToInt(byte[] bs, int off, int[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = littleEndianToInt(bs, off);
- off += 4;
- }
- }
-
- public static byte[] intToLittleEndian(int n)
- {
- byte[] bs = new byte[4];
- intToLittleEndian(n, bs, 0);
- return bs;
- }
-
- public static void intToLittleEndian(int n, byte[] bs, int off)
- {
- bs[ off] = (byte)(n );
- bs[++off] = (byte)(n >>> 8);
- bs[++off] = (byte)(n >>> 16);
- bs[++off] = (byte)(n >>> 24);
- }
-
- public static byte[] intToLittleEndian(int[] ns)
- {
- byte[] bs = new byte[4 * ns.length];
- intToLittleEndian(ns, bs, 0);
- return bs;
- }
-
- public static void intToLittleEndian(int[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- intToLittleEndian(ns[i], bs, off);
- off += 4;
- }
- }
-
- public static long littleEndianToLong(byte[] bs, int off)
- {
- int lo = littleEndianToInt(bs, off);
- int hi = littleEndianToInt(bs, off + 4);
- return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL);
- }
-
- public static void littleEndianToLong(byte[] bs, int off, long[] ns)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- ns[i] = littleEndianToLong(bs, off);
- off += 8;
- }
- }
-
- public static byte[] longToLittleEndian(long n)
- {
- byte[] bs = new byte[8];
- longToLittleEndian(n, bs, 0);
- return bs;
- }
-
- public static void longToLittleEndian(long n, byte[] bs, int off)
- {
- intToLittleEndian((int)(n & 0xffffffffL), bs, off);
- intToLittleEndian((int)(n >>> 32), bs, off + 4);
- }
-
- public static byte[] longToLittleEndian(long[] ns)
- {
- byte[] bs = new byte[8 * ns.length];
- longToLittleEndian(ns, bs, 0);
- return bs;
- }
-
- public static void longToLittleEndian(long[] ns, byte[] bs, int off)
- {
- for (int i = 0; i < ns.length; ++i)
- {
- longToLittleEndian(ns[i], bs, off);
- off += 8;
- }
- }
-}
+package org.bouncycastle.crypto.util; + +public abstract class Pack +{ + public static int bigEndianToInt(byte[] bs, int off) + { + int n = bs[ off] << 24; + n |= (bs[++off] & 0xff) << 16; + n |= (bs[++off] & 0xff) << 8; + n |= (bs[++off] & 0xff); + return n; + } + + public static void bigEndianToInt(byte[] bs, int off, int[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = bigEndianToInt(bs, off); + off += 4; + } + } + + public static byte[] intToBigEndian(int n) + { + byte[] bs = new byte[4]; + intToBigEndian(n, bs, 0); + return bs; + } + + public static void intToBigEndian(int n, byte[] bs, int off) + { + bs[ off] = (byte)(n >>> 24); + bs[++off] = (byte)(n >>> 16); + bs[++off] = (byte)(n >>> 8); + bs[++off] = (byte)(n ); + } + + public static byte[] intToBigEndian(int[] ns) + { + byte[] bs = new byte[4 * ns.length]; + intToBigEndian(ns, bs, 0); + return bs; + } + + public static void intToBigEndian(int[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + intToBigEndian(ns[i], bs, off); + off += 4; + } + } + + public static long bigEndianToLong(byte[] bs, int off) + { + int hi = bigEndianToInt(bs, off); + int lo = bigEndianToInt(bs, off + 4); + return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL); + } + + public static void bigEndianToLong(byte[] bs, int off, long[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = bigEndianToLong(bs, off); + off += 8; + } + } + + public static byte[] longToBigEndian(long n) + { + byte[] bs = new byte[8]; + longToBigEndian(n, bs, 0); + return bs; + } + + public static void longToBigEndian(long n, byte[] bs, int off) + { + intToBigEndian((int)(n >>> 32), bs, off); + intToBigEndian((int)(n & 0xffffffffL), bs, off + 4); + } + + public static byte[] longToBigEndian(long[] ns) + { + byte[] bs = new byte[8 * ns.length]; + longToBigEndian(ns, bs, 0); + return bs; + } + + public static void longToBigEndian(long[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + longToBigEndian(ns[i], bs, off); + off += 8; + } + } + + public static int littleEndianToInt(byte[] bs, int off) + { + int n = bs[ off] & 0xff; + n |= (bs[++off] & 0xff) << 8; + n |= (bs[++off] & 0xff) << 16; + n |= bs[++off] << 24; + return n; + } + + public static void littleEndianToInt(byte[] bs, int off, int[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = littleEndianToInt(bs, off); + off += 4; + } + } + + public static byte[] intToLittleEndian(int n) + { + byte[] bs = new byte[4]; + intToLittleEndian(n, bs, 0); + return bs; + } + + public static void intToLittleEndian(int n, byte[] bs, int off) + { + bs[ off] = (byte)(n ); + bs[++off] = (byte)(n >>> 8); + bs[++off] = (byte)(n >>> 16); + bs[++off] = (byte)(n >>> 24); + } + + public static byte[] intToLittleEndian(int[] ns) + { + byte[] bs = new byte[4 * ns.length]; + intToLittleEndian(ns, bs, 0); + return bs; + } + + public static void intToLittleEndian(int[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + intToLittleEndian(ns[i], bs, off); + off += 4; + } + } + + public static long littleEndianToLong(byte[] bs, int off) + { + int lo = littleEndianToInt(bs, off); + int hi = littleEndianToInt(bs, off + 4); + return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL); + } + + public static void littleEndianToLong(byte[] bs, int off, long[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = littleEndianToLong(bs, off); + off += 8; + } + } + + public static byte[] longToLittleEndian(long n) + { + byte[] bs = new byte[8]; + longToLittleEndian(n, bs, 0); + return bs; + } + + public static void longToLittleEndian(long n, byte[] bs, int off) + { + intToLittleEndian((int)(n & 0xffffffffL), bs, off); + intToLittleEndian((int)(n >>> 32), bs, off + 4); + } + + public static byte[] longToLittleEndian(long[] ns) + { + byte[] bs = new byte[8 * ns.length]; + longToLittleEndian(ns, bs, 0); + return bs; + } + + public static void longToLittleEndian(long[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + longToLittleEndian(ns[i], bs, off); + off += 8; + } + } +} diff --git a/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/src/main/java/org/bouncycastle/math/ec/ECPoint.java index ac67152a..cbc5aaf4 100644 --- a/src/main/java/org/bouncycastle/math/ec/ECPoint.java +++ b/src/main/java/org/bouncycastle/math/ec/ECPoint.java @@ -1,593 +1,593 @@ -package org.bouncycastle.math.ec;
-
-import java.math.BigInteger;
-
-import org.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 byte[] getEncoded()
- {
- return getEncoded(withCompression);
- }
-
- public abstract byte[] getEncoded(boolean compressed);
-
- 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 (k.signum() < 0)
- {
- throw new IllegalArgumentException("The multiplicator cannot be negative");
- }
-
- 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(boolean compressed)
- {
- if (this.isInfinity())
- {
- return new byte[1];
- }
-
- int qLength = converter.getByteLength(x);
-
- if (compressed)
- {
- 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, withCompression);
- }
-
- // 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);
- }
-
- /**
- * 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;
- }
-
- /* (non-Javadoc)
- * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
- */
- public byte[] getEncoded(boolean compressed)
- {
- if (this.isInfinity())
- {
- return new byte[1];
- }
-
- int byteCount = converter.getByteLength(this.x);
- byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
- byte[] PO;
-
- if (compressed)
- {
- // 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);
- }
-
- /**
- * 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();
- }
- }
- }
- }
-}
+package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +import org.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 byte[] getEncoded() + { + return getEncoded(withCompression); + } + + public abstract byte[] getEncoded(boolean compressed); + + 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 (k.signum() < 0) + { + throw new IllegalArgumentException("The multiplicator cannot be negative"); + } + + 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(boolean compressed) + { + if (this.isInfinity()) + { + return new byte[1]; + } + + int qLength = converter.getByteLength(x); + + if (compressed) + { + 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, withCompression); + } + + // 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); + } + + /** + * 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; + } + + /* (non-Javadoc) + * @see org.bouncycastle.math.ec.ECPoint#getEncoded() + */ + public byte[] getEncoded(boolean compressed) + { + if (this.isInfinity()) + { + return new byte[1]; + } + + int byteCount = converter.getByteLength(this.x); + byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount); + byte[] PO; + + if (compressed) + { + // 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); + } + + /** + * 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(); + } + } + } + } +} diff --git a/src/main/java/org/bouncycastle/util/encoders/Base64.java b/src/main/java/org/bouncycastle/util/encoders/Base64.java index 9b7d0e43..83806295 100644 --- a/src/main/java/org/bouncycastle/util/encoders/Base64.java +++ b/src/main/java/org/bouncycastle/util/encoders/Base64.java @@ -1,151 +1,151 @@ -package org.bouncycastle.util.encoders;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.bouncycastle.util.Strings;
-
-public class Base64
-{
- private static final Encoder encoder = new Base64Encoder();
-
- public static String toBase64String(
- byte[] data)
- {
- return toBase64String(data, 0, data.length);
- }
-
- public static String toBase64String(
- byte[] data,
- int off,
- int length)
- {
- byte[] encoded = encode(data, off, length);
- return Strings.fromByteArray(encoded);
- }
-
- /**
- * encode the input data producing a base 64 encoded byte array.
- *
- * @return a byte array containing the base 64 encoded data.
- */
- public static byte[] encode(
- byte[] data)
- {
- return encode(data, 0, data.length);
- }
-
- /**
- * encode the input data producing a base 64 encoded byte array.
- *
- * @return a byte array containing the base 64 encoded data.
- */
- public static byte[] encode(
- byte[] data,
- int off,
- int length)
- {
- int len = (length + 2) / 3 * 4;
- ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
-
- try
- {
- encoder.encode(data, off, length, bOut);
- }
- catch (Exception e)
- {
- throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * Encode the byte data to base 64 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);
- }
-
- /**
- * Encode the byte data to base 64 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 base 64 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)
- {
- int len = data.length / 4 * 3;
- ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
-
- try
- {
- encoder.decode(data, 0, data.length, bOut);
- }
- catch (Exception e)
- {
- throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * decode the base 64 encoded String data - whitespace will be ignored.
- *
- * @return a byte array representing the decoded data.
- */
- public static byte[] decode(
- String data)
- {
- int len = data.length() / 4 * 3;
- ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
-
- try
- {
- encoder.decode(data, bOut);
- }
- catch (Exception e)
- {
- throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e);
- }
-
- return bOut.toByteArray();
- }
-
- /**
- * decode the base 64 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);
- }
-}
+package org.bouncycastle.util.encoders; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.util.Strings; + +public class Base64 +{ + private static final Encoder encoder = new Base64Encoder(); + + public static String toBase64String( + byte[] data) + { + return toBase64String(data, 0, data.length); + } + + public static String toBase64String( + byte[] data, + int off, + int length) + { + byte[] encoded = encode(data, off, length); + return Strings.fromByteArray(encoded); + } + + /** + * encode the input data producing a base 64 encoded byte array. + * + * @return a byte array containing the base 64 encoded data. + */ + public static byte[] encode( + byte[] data) + { + return encode(data, 0, data.length); + } + + /** + * encode the input data producing a base 64 encoded byte array. + * + * @return a byte array containing the base 64 encoded data. + */ + public static byte[] encode( + byte[] data, + int off, + int length) + { + int len = (length + 2) / 3 * 4; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); + + try + { + encoder.encode(data, off, length, bOut); + } + catch (Exception e) + { + throw new EncoderException("exception encoding base64 string: " + e.getMessage(), e); + } + + return bOut.toByteArray(); + } + + /** + * Encode the byte data to base 64 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); + } + + /** + * Encode the byte data to base 64 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 base 64 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) + { + int len = data.length / 4 * 3; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); + + try + { + encoder.decode(data, 0, data.length, bOut); + } + catch (Exception e) + { + throw new DecoderException("unable to decode base64 data: " + e.getMessage(), e); + } + + return bOut.toByteArray(); + } + + /** + * decode the base 64 encoded String data - whitespace will be ignored. + * + * @return a byte array representing the decoded data. + */ + public static byte[] decode( + String data) + { + int len = data.length() / 4 * 3; + ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); + + try + { + encoder.decode(data, bOut); + } + catch (Exception e) + { + throw new DecoderException("unable to decode base64 string: " + e.getMessage(), e); + } + + return bOut.toByteArray(); + } + + /** + * decode the base 64 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); + } +} diff --git a/src/main/java/org/bouncycastle/util/encoders/Hex.java b/src/main/java/org/bouncycastle/util/encoders/Hex.java index 6a1c0f8e..d49f1ef4 100644 --- a/src/main/java/org/bouncycastle/util/encoders/Hex.java +++ b/src/main/java/org/bouncycastle/util/encoders/Hex.java @@ -1,148 +1,148 @@ -package org.bouncycastle.util.encoders;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.bouncycastle.util.Strings;
-
-public class Hex
-{
- private static final Encoder encoder = new HexEncoder();
-
- public static String toHexString(
- byte[] data)
- {
- return toHexString(data, 0, data.length);
- }
-
- public static String toHexString(
- byte[] data,
- int off,
- int length)
- {
- byte[] encoded = encode(data, off, length);
- return Strings.fromByteArray(encoded);
- }
-
- /**
- * 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 (Exception e)
- {
- throw new EncoderException("exception encoding Hex string: " + e.getMessage(), 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 (Exception e)
- {
- throw new DecoderException("exception decoding Hex data: " + e.getMessage(), 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 (Exception e)
- {
- throw new DecoderException("exception decoding Hex string: " + e.getMessage(), 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);
- }
-}
+package org.bouncycastle.util.encoders; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.util.Strings; + +public class Hex +{ + private static final Encoder encoder = new HexEncoder(); + + public static String toHexString( + byte[] data) + { + return toHexString(data, 0, data.length); + } + + public static String toHexString( + byte[] data, + int off, + int length) + { + byte[] encoded = encode(data, off, length); + return Strings.fromByteArray(encoded); + } + + /** + * 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 (Exception e) + { + throw new EncoderException("exception encoding Hex string: " + e.getMessage(), 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 (Exception e) + { + throw new DecoderException("exception decoding Hex data: " + e.getMessage(), 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 (Exception e) + { + throw new DecoderException("exception decoding Hex string: " + e.getMessage(), 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); + } +} |