All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ratpack.session.clientside.internal.DefaultCrypto Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ratpack.session.clientside.internal;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import ratpack.session.clientside.Crypto;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class DefaultCrypto implements Crypto {

  private final SecretKeySpec secretKeySpec;
  private final String algorithm;
  private final boolean isInitializationVectorRequired;
  private final boolean hasPadding;

  public DefaultCrypto(byte[] key, String algorithm) {
    String[] parts = algorithm.split("/");
    this.secretKeySpec = new SecretKeySpec(key, parts[0]);
    this.algorithm = algorithm;
    this.isInitializationVectorRequired = parts.length > 1 && !parts[1].equalsIgnoreCase("ECB");
    this.hasPadding = parts.length <= 2 || !parts[2].equals("NoPadding");
  }

  @Override
  public ByteBuf encrypt(ByteBuf message, ByteBufAllocator allocator) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, ShortBufferException, IllegalBlockSizeException {
    Cipher cipher = Cipher.getInstance(algorithm);
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

    int blockSize = cipher.getBlockSize();
    int messageLength = message.readableBytes();
    int encMessageLength = cipher.getOutputSize(messageLength);

    ByteBuf paddedMessage = null;
    if (!hasPadding && messageLength == encMessageLength && (encMessageLength % blockSize) != 0) {
      int paddedMessageSize = messageLength + blockSize - (messageLength % blockSize);
      paddedMessage = allocator.buffer(paddedMessageSize);
      paddedMessage.setZero(0, paddedMessageSize);
      paddedMessage.setBytes(0, message, messageLength);
      paddedMessage.writerIndex(paddedMessageSize);
      encMessageLength = cipher.getOutputSize(paddedMessageSize);
    }

    ByteBuf encMessage = allocator.buffer(encMessageLength);
    ByteBuffer nioBuffer = encMessage.nioBuffer(0, encMessageLength);
    cipher.doFinal(paddedMessage == null ? message.nioBuffer() : paddedMessage.nioBuffer(), nioBuffer);
    encMessage.writerIndex(encMessageLength);

    if (paddedMessage != null) {
      paddedMessage.release();
    }

    if (isInitializationVectorRequired) {
      byte[] ivBytes = cipher.getIV();
      ByteBuf iv = allocator.buffer(1 + ivBytes.length);
      iv.writeByte(ivBytes.length).writeBytes(ivBytes);
      return Unpooled.wrappedBuffer(2, iv, encMessage);
    } else {
      return encMessage;
    }
  }

  @Override
  public ByteBuf decrypt(ByteBuf message, ByteBufAllocator allocator) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, ShortBufferException, IllegalBlockSizeException {
    Cipher cipher = Cipher.getInstance(algorithm);

    if (isInitializationVectorRequired) {
      int ivByteLength = message.readByte();
      byte[] iv = new byte[ivByteLength];
      message.readBytes(iv);
      cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(iv));
    } else {
      cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    }

    int messageLength = message.readableBytes();
    ByteBuf decMessage = allocator.buffer(cipher.getOutputSize(messageLength));
    ByteBuf byteBuf = message.readBytes(messageLength);

    try {
      int count = cipher.doFinal(byteBuf.nioBuffer(), decMessage.nioBuffer(0, messageLength));
      if (!hasPadding) {
        for (int i = count - 1; i >= 0; i--) {
          if (decMessage.getByte(i) == 0x00) {
            count--;
          } else {
            break;
          }
        }
      }
      decMessage.writerIndex(count);
      return decMessage;
    } catch (Exception e) {
      decMessage.release();
      throw e;
    } finally {
      byteBuf.release();
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy