Author: bayard Date: Fri Mar 7 23:51:41 2008 New Revision: 634904 URL: http://svn.apache.org/viewvc?rev=634904&view=rev Log: Adding Chris Black's patch from CODEC-40 adding BigInteger support to Base64. Still needs edge case testing
Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java?rev=634904&r1=634903&r2=634904&view=diff ============================================================================== --- commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java (original) +++ commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java Fri Mar 7 23:51:41 2008 @@ -22,6 +22,8 @@ import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; +import java.math.BigInteger; + /** * Provides Base64 encoding and decoding as defined by RFC 2045. * @@ -532,4 +534,67 @@ return encodeBase64(pArray, false); } + // Implementation of integer encoding used for crypto + /** + * Decode a byte64-encoded integer according to crypto + * standards such as W3C's XML-Signature + * + * @param pArray a byte array containing base64 character data + * @return A BigInteger + */ + public static BigInteger decodeInteger(byte[] pArray) { + return new BigInteger(1, decodeBase64(pArray)); + } + + /** + * Encode to a byte64-encoded integer according to crypto + * standards such as W3C's XML-Signature + * + * @param bigInt a BigInteger + * @return A byte array containing base64 character data + * @throws NullPointerException if null is passed in + */ + public static byte[] encodeInteger(BigInteger bigInt) { + if(bigInt == null) { + throw new NullPointerException("encodeInteger called with null parameter"); + } + + return encodeBase64(toIntegerBytes(bigInt), false); + } + + /** + * Returns a byte-array representation of a <code>BigInteger</code> + * without sign bit. + * + * @param bigInt <code>BigInteger</code> to be converted + * @return a byte array representation of the BigInteger parameter + */ + static byte[] toIntegerBytes(BigInteger bigInt) { + int bitlen = bigInt.bitLength(); + // round bitlen + bitlen = ((bitlen + 7) >> 3) << 3; + byte[] bigBytes = bigInt.toByteArray(); + + if(((bigInt.bitLength() % 8) != 0) + && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { + return bigBytes; + } + + // set up params for copying everything but sign bit + int startSrc = 0; + int len = bigBytes.length; + + // if bigInt is exactly byte-aligned, just skip signbit in copy + if((bigInt.bitLength() % 8) == 0) { + startSrc = 1; + len--; + } + + int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec + byte[] resizedBytes = new byte[bitlen / 8]; + + System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); + + return resizedBytes; + } } Modified: commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java?rev=634904&r1=634903&r2=634904&view=diff ============================================================================== --- commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java (original) +++ commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64Test.java Fri Mar 7 23:51:41 2008 @@ -20,7 +20,7 @@ import java.util.Arrays; import java.util.Random; - +import java.math.BigInteger; import junit.framework.TestCase; /** @@ -636,6 +636,55 @@ destFromWS.equals( orig ) ); assertTrue( "Dest string doesn't eausl original", destFromNoWS.equals( orig ) ); + } + + public void testCodeInteger1() { + String encodedInt1 = "li7dzDacuo67Jg7mtqEm2TRuOMU="; + BigInteger bigInt1 = new BigInteger("85739377120809420210425962799" + + "0318636601332086981"); + + assertEquals(encodedInt1, new String(Base64.encodeInteger(bigInt1))); + assertEquals(bigInt1, Base64.decodeInteger(encodedInt1.getBytes())); + } + + public void testCodeInteger2() { + String encodedInt2 = "9B5ypLY9pMOmtxCeTDHgwdNFeGs="; + BigInteger bigInt2 = new BigInteger("13936727572861167254666467268" + + "91466679477132949611"); + + assertEquals(encodedInt2, new String(Base64.encodeInteger(bigInt2))); + assertEquals(bigInt2, Base64.decodeInteger(encodedInt2.getBytes())); + } + + public void testCodeInteger3() { + String encodedInt3 = "FKIhdgaG5LGKiEtF1vHy4f3y700zaD6QwDS3IrNVGzNp2" + + "rY+1LFWTK6D44AyiC1n8uWz1itkYMZF0/aKDK0Yjg=="; + BigInteger bigInt3 = new BigInteger("10806548154093873461951748545" + + "1196989136416448805819079363524309897749044958112417136240557" + + "4495062430572478766856090958495998158114332651671116876320938126"); + + assertEquals(encodedInt3, new String(Base64.encodeInteger(bigInt3))); + assertEquals(bigInt3, Base64.decodeInteger(encodedInt3.getBytes())); + } + + public void testCodeInteger4() { + String encodedInt4 = "ctA8YGxrtngg/zKVvqEOefnwmViFztcnPBYPlJsvh6yKI" + + "4iDm68fnp4Mi3RrJ6bZAygFrUIQLxLjV+OJtgJAEto0xAs+Mehuq1DkSFEpP3o" + + "DzCTOsrOiS1DwQe4oIb7zVk/9l7aPtJMHW0LVlMdwZNFNNJoqMcT2ZfCPrfvYv" + + "Q0="; + BigInteger bigInt4 = new BigInteger("80624726256040348115552042320" + + "6968135001872753709424419772586693950232350200555646471175944" + + "519297087885987040810778908507262272892702303774422853675597" + + "748008534040890923814202286633163248086055216976551456088015" + + "338880713818192088877057717530169381044092839402438015097654" + + "53542091716518238707344493641683483917"); + + assertEquals(encodedInt4, new String(Base64.encodeInteger(bigInt4))); + assertEquals(bigInt4, Base64.decodeInteger(encodedInt4.getBytes())); + } + + public void testCodeIntegerEdgeCases() { + // TODO } // -------------------------------------------------------- Private Methods