Skip to content

Commit

Permalink
Merge branch '__rultor'
Browse files Browse the repository at this point in the history
  • Loading branch information
rultor committed Feb 19, 2016
2 parents b2e04e1 + 796ce43 commit 62a117f
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 98 deletions.
103 changes: 55 additions & 48 deletions src/main/java/org/takes/facets/auth/codecs/CcAES.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import lombok.EqualsAndHashCode;
Expand All @@ -44,77 +43,53 @@
* AES codec which supports 128 bits key.
*
* <p>The class is immutable and thread-safe.
*
* @author Jason Wong (super132j@yahoo.com)
* @version $Id$
* @since 0.13.8
*/
@EqualsAndHashCode(of = { "origin", "secret", "enc", "dec" })
@EqualsAndHashCode(of = {"origin", "key", "spec"})
public final class CcAES implements Codec {

/**
* The cipher for encryption.
* The block size constant.
*/
private final transient Cipher enc;
private static final int BLOCK = 16;

/**
* The cipher for decryption.
* Original codec.
*/
private final transient Cipher dec;
private final transient Codec origin;

/**
* Original codec.
* The encryption key.
*/
private final transient Codec origin;
private final transient byte[] key;

/**
* The AES secret key object.
* The algorithm parameter spec for cipher.
*/
private final transient SecretKey secret;
private final transient AlgorithmParameterSpec spec;

/**
* Ctor.
* Constructor for the class.
*
* @param codec Original codec
* @param key The encryption key
* @exception IOException errors on creating internal components
* @since 0.22
*/
public CcAES(final Codec codec, final String key) throws IOException {
public CcAES(final Codec codec, final String key) {
this(codec, key.getBytes(Charset.defaultCharset()));
}

/**
* Ctor.
* Constructor for the class.
*
* @param codec Original codec
* @param key The encryption key
* @exception IOException errors on creating internal components
* @todo #558:30min CcAES ctor. According to new qulice version, constructor
* must contain only variables initialization and other constructor calls.
* Refactor code according to that rule and remove
* `ConstructorOnlyInitializesOrCallOtherConstructors`
* warning suppression.
*/
@SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors")
public CcAES(final Codec codec, final byte[] key) throws IOException {
final int block = 16;
if (key.length != block) {
throw new IllegalArgumentException(
String.format(
"the length of the AES key must be exactly %d bytes",
block
)
);
}
public CcAES(final Codec codec, final byte[] key) {
this.origin = codec;
final byte[] passcode = new byte[key.length];
System.arraycopy(key, 0, passcode, 0, key.length);
final SecureRandom random = new SecureRandom();
final byte[] ivbytes = new byte[block];
random.nextBytes(ivbytes);
final AlgorithmParameterSpec spec = new IvParameterSpec(ivbytes);
this.secret = new SecretKeySpec(passcode, "AES");
this.enc = this.create(Cipher.ENCRYPT_MODE, spec);
this.dec = this.create(Cipher.DECRYPT_MODE, spec);
this.key = key.clone();
this.spec = CcAES.algorithmParameterSpec();
}

@Override
Expand All @@ -136,14 +111,44 @@ public Identity decode(final byte[] bytes) throws IOException {
*/
private byte[] encrypt(final byte[] bytes) throws IOException {
try {
return this.enc.doFinal(bytes);
return this.create(Cipher.ENCRYPT_MODE).doFinal(bytes);
} catch (final BadPaddingException ex) {
throw new IOException(ex);
} catch (final IllegalBlockSizeException ex) {
throw new IOException(ex);
}
}

/**
* Create AlgorithmParameterSpec with the block size.
*
* @return The AlgorithmParameterSpec
*/
private static AlgorithmParameterSpec algorithmParameterSpec() {
final SecureRandom random = new SecureRandom();
final byte[] bytes = new byte[CcAES.BLOCK];
random.nextBytes(bytes);
return new IvParameterSpec(bytes);
}

/**
* Check the block size of the key.
*
* @param key The encryption key
* @return The verified encryption key
*/
private static byte[] withCorrectBlockSize(final byte[] key) {
if (key.length != CcAES.BLOCK) {
throw new IllegalArgumentException(
String.format(
"the length of the AES key must be exactly %d bytes",
CcAES.BLOCK
)
);
}
return key;
}

/**
* Decrypt the given bytes using AES.
*
Expand All @@ -153,7 +158,7 @@ private byte[] encrypt(final byte[] bytes) throws IOException {
*/
private byte[] decrypt(final byte[] bytes) throws IOException {
try {
return this.dec.doFinal(bytes);
return this.create(Cipher.DECRYPT_MODE).doFinal(bytes);
} catch (final BadPaddingException ex) {
throw new IOException(ex);
} catch (final IllegalBlockSizeException ex) {
Expand All @@ -163,16 +168,19 @@ private byte[] decrypt(final byte[] bytes) throws IOException {

/**
* Create new cipher based on the valid mode from {@link Cipher} class.
*
* @param mode Either Cipher.ENRYPT_MODE or Cipher.DECRYPT_MODE
* @param spec The algorithm parameter spec for cipher creation
* @return The cipher
* @throws IOException For any unexpected exceptions
*/
private Cipher create(final int mode, final AlgorithmParameterSpec spec)
private Cipher create(final int mode)
throws IOException {
try {
final SecretKeySpec secret = new SecretKeySpec(
CcAES.withCorrectBlockSize(this.key), "AES"
);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(mode, this.secret, spec);
cipher.init(mode, secret, this.spec);
return cipher;
} catch (final InvalidKeyException ex) {
throw new IOException(ex);
Expand All @@ -184,5 +192,4 @@ private Cipher create(final int mode, final AlgorithmParameterSpec spec)
throw new IOException(ex);
}
}

}
84 changes: 34 additions & 50 deletions src/test/java/org/takes/tk/TkProxyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.takes.http.FtRemote;
import org.takes.rq.RqFake;
import org.takes.rq.RqHref;
import org.takes.rq.RqMethod;
import org.takes.rs.RsPrint;
import org.takes.rs.RsText;

Expand All @@ -44,49 +43,37 @@
* @version $Id$
* @since 0.25
* @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
* @todo #377:30min/DEV We need more tests for TkProxy.
* The tests should verify the different HTTP methods (GET, POST, etc),
* as well as the different combinations of request/response headers.
*/
public final class TkProxyTest {

/**
* An array of http methods for testing.
*/
private static final String[] METHODS = {
RqMethod.POST,
RqMethod.GET,
RqMethod.PUT,
RqMethod.DELETE,
RqMethod.TRACE,
};

/**
* TkProxy can just work.
* TkProxy can work.
* @throws Exception If some problem inside
*/
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
@Test
public void justWorks() throws Exception {
for (final String method:TkProxyTest.METHODS) {
new FtRemote(new TkFixed("hello, world!")).exec(
new FtRemote.Script() {
@Override
public void exec(final URI home) throws IOException {
MatcherAssert.assertThat(
new RsPrint(
new TkProxy(home).act(new RqFake(method))
).print(),
Matchers.containsString("hello")
);
}
new FtRemote(new TkFixed("hello, world!")).exec(
new FtRemote.Script() {
@Override
public void exec(final URI home) throws IOException {
MatcherAssert.assertThat(
new RsPrint(
new TkProxy(home).act(new RqFake("PUT"))
).print(),
Matchers.containsString("hello")
);
}
);
}
}
);
}

/**
* TkProxy can correctly maps path string.
* TkProxy can work.
* @throws Exception If some problem inside
*/
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
@Test
public void correctlyMapsPathString() throws Exception {
final Take take = new Take() {
Expand All @@ -95,27 +82,24 @@ public Response act(final Request req) throws IOException {
return new RsText(new RqHref.Base(req).href().toString());
}
};
for (final String method:TkProxyTest.METHODS) {
new FtRemote(take).exec(
new FtRemote.Script() {
@Override
public void exec(final URI home) throws IOException {
MatcherAssert.assertThat(
new RsPrint(
new TkProxy(home).act(
new RqFake(method, "/a/b/c")
)
).printBody(),
Matchers.equalTo(
String.format(
"http://%s:%d/a/b/c",
home.getHost(), home.getPort()
)
new FtRemote(take).exec(
new FtRemote.Script() {
@Override
public void exec(final URI home) throws IOException {
MatcherAssert.assertThat(
new RsPrint(
new TkProxy(home).act(new RqFake("GET", "/a/b/c"))
).printBody(),
Matchers.equalTo(
String.format(
"http://%s:%d/a/b/c",
home.getHost(), home.getPort()
)
);
}
)
);
}
);
}
}
);
}

}

0 comments on commit 62a117f

Please sign in to comment.