package com.hwlcn.security.crypto; import com.hwlcn.security.util.StringUtils; public class DefaultBlockCipherService extends AbstractSymmetricCipherService { private static final int DEFAULT_BLOCK_SIZE = 0; private static final String TRANSFORMATION_STRING_DELIMITER = "/"; private static final int DEFAULT_STREAMING_BLOCK_SIZE = 8; //8 bits (1 byte) private String modeName; private int blockSize; private String paddingSchemeName; private String streamingModeName; private int streamingBlockSize; private String streamingPaddingSchemeName; private String transformationString; private String streamingTransformationString; public DefaultBlockCipherService(String algorithmName) { super(algorithmName); this.modeName = OperationMode.CBC.name(); this.paddingSchemeName = PaddingScheme.PKCS5.getTransformationName(); this.blockSize = DEFAULT_BLOCK_SIZE; this.streamingModeName = OperationMode.CBC.name(); this.streamingPaddingSchemeName = PaddingScheme.PKCS5.getTransformationName(); this.streamingBlockSize = DEFAULT_STREAMING_BLOCK_SIZE; } public String getModeName() { return modeName; } public void setModeName(String modeName) { this.modeName = modeName; this.transformationString = null; } public void setMode(OperationMode mode) { setModeName(mode.name()); } public String getPaddingSchemeName() { return paddingSchemeName; } public void setPaddingSchemeName(String paddingSchemeName) { this.paddingSchemeName = paddingSchemeName; this.transformationString = null; } public void setPaddingScheme(PaddingScheme paddingScheme) { setPaddingSchemeName(paddingScheme.getTransformationName()); } public int getBlockSize() { return blockSize; } public void setBlockSize(int blockSize) { this.blockSize = Math.max(DEFAULT_BLOCK_SIZE, blockSize); this.transformationString = null; } public String getStreamingModeName() { return streamingModeName; } private boolean isModeStreamingCompatible(String modeName) { return modeName != null && !modeName.equalsIgnoreCase(OperationMode.ECB.name()) && !modeName.equalsIgnoreCase(OperationMode.NONE.name()); } public void setStreamingModeName(String streamingModeName) { if (!isModeStreamingCompatible(streamingModeName)) { String msg = "mode [" + streamingModeName + "] is not a valid operation mode for block cipher streaming."; throw new IllegalArgumentException(msg); } this.streamingModeName = streamingModeName; this.streamingTransformationString = null; } public void setStreamingMode(OperationMode mode) { setStreamingModeName(mode.name()); } public String getStreamingPaddingSchemeName() { return streamingPaddingSchemeName; } public void setStreamingPaddingSchemeName(String streamingPaddingSchemeName) { this.streamingPaddingSchemeName = streamingPaddingSchemeName; this.streamingTransformationString = null; } public void setStreamingPaddingScheme(PaddingScheme scheme) { setStreamingPaddingSchemeName(scheme.getTransformationName()); } public int getStreamingBlockSize() { return streamingBlockSize; } public void setStreamingBlockSize(int streamingBlockSize) { this.streamingBlockSize = Math.max(DEFAULT_BLOCK_SIZE, streamingBlockSize); this.streamingTransformationString = null; } protected String getTransformationString(boolean streaming) { if (streaming) { if (this.streamingTransformationString == null) { this.streamingTransformationString = buildStreamingTransformationString(); } return this.streamingTransformationString; } else { if (this.transformationString == null) { this.transformationString = buildTransformationString(); } return this.transformationString; } } private String buildTransformationString() { return buildTransformationString(getModeName(), getPaddingSchemeName(), getBlockSize()); } private String buildStreamingTransformationString() { return buildTransformationString(getStreamingModeName(), getStreamingPaddingSchemeName(), 0); } private String buildTransformationString(String modeName, String paddingSchemeName, int blockSize) { StringBuilder sb = new StringBuilder(getAlgorithmName()); if (StringUtils.hasText(modeName)) { sb.append(TRANSFORMATION_STRING_DELIMITER).append(modeName); } if (blockSize > 0) { sb.append(blockSize); } if (StringUtils.hasText(paddingSchemeName)) { sb.append(TRANSFORMATION_STRING_DELIMITER).append(paddingSchemeName); } return sb.toString(); } private boolean isModeInitializationVectorCompatible(String modeName) { return modeName != null && !modeName.equalsIgnoreCase(OperationMode.ECB.name()) && !modeName.equalsIgnoreCase(OperationMode.NONE.name()); } @Override protected boolean isGenerateInitializationVectors(boolean streaming) { return streaming || super.isGenerateInitializationVectors() && isModeInitializationVectorCompatible(getModeName()); } @Override protected byte[] generateInitializationVector(boolean streaming) { if (streaming) { String streamingModeName = getStreamingModeName(); if (!isModeInitializationVectorCompatible(streamingModeName)) { String msg = "streamingMode attribute value [" + streamingModeName + "] does not support " + "Initialization Vectors. Ensure the streamingMode value represents an operation mode " + "that is compatible with initialization vectors."; throw new IllegalStateException(msg); } } else { String modeName = getModeName(); if (!isModeInitializationVectorCompatible(modeName)) { String msg = "mode attribute value [" + modeName + "] does not support " + "Initialization Vectors. Ensure the mode value represents an operation mode " + "that is compatible with initialization vectors."; throw new IllegalStateException(msg); } } return super.generateInitializationVector(streaming); } }