更新
This commit is contained in:
@ -61,13 +61,14 @@ public class OperationLogServiceImpl implements OperationLogService {
|
||||
operationLog.setMethod(element.getMethodName());
|
||||
}
|
||||
BaseCacheUser user = cacheUserService.getCacheUser();
|
||||
|
||||
operationLog.setUser(user);
|
||||
if (null != user) {
|
||||
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
|
||||
// 提取token头信息 ;
|
||||
operationLog.setToken(request.getHeader(AUTHORIZATION_HEADER))
|
||||
.setUser(user)
|
||||
.setUrl(request.getMethod() + "." + request.getRequestURI());
|
||||
if (request != null) {
|
||||
// 提取token头信息 ;
|
||||
operationLog.setToken(request.getHeader(AUTHORIZATION_HEADER))
|
||||
.setUrl(request.getMethod() + "." + request.getRequestURI());
|
||||
}
|
||||
}
|
||||
|
||||
operationLog.setId(PropertyUtils.getSnowflakeId())
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.chinaunicom.mall.ebtp.common.util;
|
||||
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
@ -27,7 +28,11 @@ public final class HttpContextUtils {
|
||||
* @return HttpServletRequest
|
||||
*/
|
||||
public static HttpServletRequest getHttpServletRequest() {
|
||||
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes != null) {
|
||||
return ((ServletRequestAttributes) requestAttributes).getRequest();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,6 +41,10 @@ public final class HttpContextUtils {
|
||||
* @return
|
||||
*/
|
||||
public static HttpServletResponse getHttpServletResponse() {
|
||||
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes != null) {
|
||||
return ((ServletRequestAttributes) requestAttributes).getResponse();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.exception;
|
||||
|
||||
public class BaseException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public BaseException(String message, Throwable parent) {
|
||||
super(message, parent);
|
||||
}
|
||||
|
||||
public BaseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BaseException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 DTCC, Fujitsu Australia Software Technology - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.exception;
|
||||
|
||||
public class CryptoException extends BaseException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public CryptoException(String message, Exception parent) {
|
||||
super(message, parent);
|
||||
}
|
||||
|
||||
public CryptoException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 DTCC, Fujitsu Australia Software Technology - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.exception;
|
||||
|
||||
/*
|
||||
Exception that is thrown from Chaincode
|
||||
*/
|
||||
public class InvalidArgumentException extends BaseException {
|
||||
private static final long serialVersionUID = -6094512275378074427L;
|
||||
|
||||
public InvalidArgumentException(String message, Exception parent) {
|
||||
super(message, parent);
|
||||
}
|
||||
|
||||
public InvalidArgumentException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidArgumentException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
}
|
@ -1,606 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016, 2017 IBM, DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.helper;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* Config allows for a global config of the toolkit. Central location for all
|
||||
* toolkit configuration defaults. Has a local config file that can override any
|
||||
* property defaults. Config file can be relocated via a system property
|
||||
* "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.configuration". Any property can be overridden
|
||||
* with environment variable and then overridden
|
||||
* with a java system property. Property hierarchy goes System property
|
||||
* overrides environment variable which overrides config file for default values specified here.
|
||||
*/
|
||||
|
||||
public class Config {
|
||||
private static final Log logger = LogFactory.getLog(Config.class);
|
||||
|
||||
private static final String DEFAULT_CONFIG = "config.properties";
|
||||
public static final String ORG_HYPERLEDGER_FABRIC_SDK_CONFIGURATION = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.configuration";
|
||||
|
||||
private static final String DEFAULT_NULL = "\0DEFAULT_NULL\0".intern(); // Used to set value to NULL since null won't work.
|
||||
/**
|
||||
* Timeout settings
|
||||
**/
|
||||
public static final String PROPOSAL_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.proposal.wait.time";
|
||||
public static final String CHANNEL_CONFIG_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.channelconfig.wait_time";
|
||||
public static final String TRANSACTION_CLEANUP_UP_TIMEOUT_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.client.transaction_cleanup_up_timeout_wait_time";
|
||||
public static final String ORDERER_RETRY_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.orderer_retry.wait_time";
|
||||
public static final String ORDERER_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.orderer.ordererWaitTimeMilliSecs";
|
||||
public static final String PEER_EVENT_REGISTRATION_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.peer.eventRegistration.wait_time";
|
||||
public static final String PEER_EVENT_RETRY_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.peer.retry_wait_time";
|
||||
public static final String PEER_EVENT_RECONNECTION_WARNING_RATE = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.peer.reconnection_warning_rate";
|
||||
public static final String GENESISBLOCK_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.channel.genesisblock_wait_time";
|
||||
/**
|
||||
* Crypto configuration settings -- settings should not be changed.
|
||||
**/
|
||||
public static final String DEFAULT_CRYPTO_SUITE_FACTORY = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.crypto.default_crypto_suite_factory";
|
||||
public static final String SECURITY_LEVEL = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security_level";
|
||||
public static final String SECURITY_PROVIDER_CLASS_NAME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security_provider_class_name";
|
||||
public static final String SECURITY_CURVE_MAPPING = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security_curve_mapping";
|
||||
public static final String HASH_ALGORITHM = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.hash_algorithm";
|
||||
public static final String ASYMMETRIC_KEY_TYPE = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.crypto.asymmetric_key_type";
|
||||
public static final String CERTIFICATE_FORMAT = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.crypto.certificate_format";
|
||||
public static final String SIGNATURE_ALGORITHM = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.crypto.default_signature_algorithm";
|
||||
/**
|
||||
* Logging settings
|
||||
**/
|
||||
public static final String MAX_LOG_STRING_LENGTH = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.log.stringlengthmax";
|
||||
public static final String EXTRALOGLEVEL = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.log.extraloglevel"; // ORG_HYPERLEDGER_FABRIC_SDK_LOG_EXTRALOGLEVEL
|
||||
public static final String LOGGERLEVEL = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.loglevel"; // ORG_HYPERLEDGER_FABRIC_SDK_LOGLEVEL=TRACE,DEBUG
|
||||
public static final String DIAGNOTISTIC_FILE_DIRECTORY = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.diagnosticFileDir"; //ORG_HYPERLEDGER_FABRIC_SDK_DIAGNOSTICFILEDIR
|
||||
|
||||
/**
|
||||
* Connections settings
|
||||
*/
|
||||
|
||||
public static final String CONN_SSL_PROVIDER = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.connections.ssl.sslProvider";
|
||||
public static final String CONN_SSL_NEGTYPE = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.connections.ssl.negotiationType";
|
||||
|
||||
/**
|
||||
* Default HFClient thread executor settings.
|
||||
*/
|
||||
|
||||
public static final String CLIENT_THREAD_EXECUTOR_COREPOOLSIZE = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.client.thread_executor_corepoolsize";
|
||||
public static final String CLIENT_THREAD_EXECUTOR_MAXIMUMPOOLSIZE = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.client.thread_executor_maximumpoolsize";
|
||||
public static final String CLIENT_THREAD_EXECUTOR_KEEPALIVETIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.client.thread_executor_keepalivetime";
|
||||
public static final String CLIENT_THREAD_EXECUTOR_KEEPALIVETIMEUNIT = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.client.thread_executor_keepalivetimeunit";
|
||||
|
||||
/**
|
||||
* Miscellaneous settings
|
||||
**/
|
||||
public static final String PROPOSAL_CONSISTENCY_VALIDATION = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.proposal.consistency_validation";
|
||||
|
||||
public static final String SERVICE_DISCOVER_FREQ_SECONDS = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.service_discovery.frequency_sec";
|
||||
public static final String SERVICE_DISCOVER_WAIT_TIME = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.service_discovery.discovery_wait_time";
|
||||
public static final String SERVICE_DISCOVER_AS_LOCALHOST = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.service_discovery.as_localhost";
|
||||
|
||||
public static final String LIFECYCLE_CHAINCODE_ENDORSEMENT_PLUGIN = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.lifecycle.chaincode_endorsement_plugin"; //ORG_HYPERLEDGER_FABRIC_SDK_LIFECYCLE_CHAINCODE_ENDORSEMENT_PLUGIN
|
||||
|
||||
public static final String LIFECYCLE_CHAINCODE_VALIDATION_PLUGIN = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.lifecycle.chaincode_validation_plugin"; //ORG_HYPERLEDGER_FABRIC_SDK_LIFECYCLE_CHAINCODE_VALIDATION_PLUGIN
|
||||
public static final String LIFECYCLE_INITREQUIREDDEFAULT = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.lifecycle.initRequiredDefault"; //ORG_HYPERLEDGER_FABRIC_SDK_LIFECYCLE_INITREQUIREDDEFAULT
|
||||
|
||||
private static Config config;
|
||||
private static final Properties sdkProperties = new Properties();
|
||||
private static final AtomicLong count = new AtomicLong(0);
|
||||
|
||||
//Provides a unique id for logging to identify a specific instance.
|
||||
public String getNextID() {
|
||||
return "" + count.incrementAndGet();
|
||||
}
|
||||
|
||||
private Config() {
|
||||
File loadFile;
|
||||
FileInputStream configProps;
|
||||
|
||||
try {
|
||||
loadFile = new File(System.getProperty(ORG_HYPERLEDGER_FABRIC_SDK_CONFIGURATION, DEFAULT_CONFIG))
|
||||
.getAbsoluteFile();
|
||||
logger.debug(format("Loading configuration from %s and it is present: %b", loadFile.toString(),
|
||||
loadFile.exists()));
|
||||
configProps = new FileInputStream(loadFile);
|
||||
sdkProperties.load(configProps);
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.warn(format("Failed to load any configuration from: %s. Using toolkit defaults",
|
||||
DEFAULT_CONFIG));
|
||||
} finally {
|
||||
|
||||
// Default values
|
||||
/**
|
||||
* Timeout settings
|
||||
**/
|
||||
defaultProperty(PROPOSAL_WAIT_TIME, "120000");
|
||||
defaultProperty(CHANNEL_CONFIG_WAIT_TIME, "15000");
|
||||
defaultProperty(ORDERER_RETRY_WAIT_TIME, "200");
|
||||
defaultProperty(ORDERER_WAIT_TIME, "10000");
|
||||
defaultProperty(PEER_EVENT_REGISTRATION_WAIT_TIME, "5000");
|
||||
defaultProperty(PEER_EVENT_RETRY_WAIT_TIME, "500");
|
||||
defaultProperty(GENESISBLOCK_WAIT_TIME, "5000");
|
||||
/**
|
||||
* This will NOT complete any transaction futures time out and must be kept WELL above any expected future timeout
|
||||
* for transactions sent to the Orderer. For internal cleanup only.
|
||||
*/
|
||||
|
||||
defaultProperty(TRANSACTION_CLEANUP_UP_TIMEOUT_WAIT_TIME, "600000"); //10 min.
|
||||
|
||||
/**
|
||||
* Crypto configuration settings
|
||||
**/
|
||||
defaultProperty(DEFAULT_CRYPTO_SUITE_FACTORY, "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security.HLSDKJCryptoSuiteFactory");
|
||||
defaultProperty(SECURITY_LEVEL, "256");
|
||||
defaultProperty(SECURITY_PROVIDER_CLASS_NAME, BouncyCastleProvider.class.getName());
|
||||
defaultProperty(SECURITY_CURVE_MAPPING, "256=secp256r1:384=secp384r1");
|
||||
defaultProperty(HASH_ALGORITHM, "SHA2");
|
||||
defaultProperty(ASYMMETRIC_KEY_TYPE, "EC");
|
||||
|
||||
defaultProperty(CERTIFICATE_FORMAT, "X.509");
|
||||
defaultProperty(SIGNATURE_ALGORITHM, "SHA256withECDSA");
|
||||
|
||||
/**
|
||||
* Connection defaults
|
||||
*/
|
||||
|
||||
defaultProperty(CONN_SSL_PROVIDER, "openSSL");
|
||||
defaultProperty(CONN_SSL_NEGTYPE, "TLS");
|
||||
|
||||
/**
|
||||
* Default HFClient thread executor settings.
|
||||
*/
|
||||
|
||||
defaultProperty(CLIENT_THREAD_EXECUTOR_COREPOOLSIZE, "0");
|
||||
defaultProperty(CLIENT_THREAD_EXECUTOR_MAXIMUMPOOLSIZE, "" + Integer.MAX_VALUE);
|
||||
defaultProperty(CLIENT_THREAD_EXECUTOR_KEEPALIVETIME, "" + "60");
|
||||
defaultProperty(CLIENT_THREAD_EXECUTOR_KEEPALIVETIMEUNIT, "SECONDS");
|
||||
|
||||
/**
|
||||
* Logging settings
|
||||
**/
|
||||
defaultProperty(MAX_LOG_STRING_LENGTH, "64");
|
||||
defaultProperty(EXTRALOGLEVEL, "0");
|
||||
defaultProperty(LOGGERLEVEL, null);
|
||||
defaultProperty(DIAGNOTISTIC_FILE_DIRECTORY, null);
|
||||
/**
|
||||
* Miscellaneous settings
|
||||
*/
|
||||
defaultProperty(PROPOSAL_CONSISTENCY_VALIDATION, "true");
|
||||
defaultProperty(PEER_EVENT_RECONNECTION_WARNING_RATE, "50");
|
||||
|
||||
defaultProperty(SERVICE_DISCOVER_FREQ_SECONDS, "120");
|
||||
defaultProperty(SERVICE_DISCOVER_WAIT_TIME, "5000");
|
||||
defaultProperty(SERVICE_DISCOVER_AS_LOCALHOST, "false");
|
||||
defaultProperty(LIFECYCLE_CHAINCODE_ENDORSEMENT_PLUGIN, DEFAULT_NULL);
|
||||
defaultProperty(LIFECYCLE_CHAINCODE_VALIDATION_PLUGIN, DEFAULT_NULL);
|
||||
defaultProperty(LIFECYCLE_INITREQUIREDDEFAULT, DEFAULT_NULL);
|
||||
|
||||
final String inLogLevel = sdkProperties.getProperty(LOGGERLEVEL);
|
||||
|
||||
if (null != inLogLevel) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* getConfig return back singleton for SDK configuration.
|
||||
*
|
||||
* @return Global configuration
|
||||
*/
|
||||
public static Config getConfig() {
|
||||
if (null == config) {
|
||||
config = new Config();
|
||||
}
|
||||
return config;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* getProperty return back property for the given value.
|
||||
*
|
||||
* @param property
|
||||
* @return String value for the property
|
||||
*/
|
||||
private String getProperty(String property) {
|
||||
|
||||
if (!sdkProperties.containsKey(property)) {
|
||||
logger.warn(format("No configuration value found for '%s'", property));
|
||||
}
|
||||
String ret = sdkProperties.getProperty(property);
|
||||
if (DEFAULT_NULL.equals(ret)) {
|
||||
ret = null;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void defaultProperty(String key, String value) {
|
||||
|
||||
String ret = System.getProperty(key);
|
||||
if (ret != null) {
|
||||
sdkProperties.put(key, ret);
|
||||
} else {
|
||||
String envKey = key.toUpperCase().replaceAll("\\.", "_");
|
||||
ret = System.getenv(envKey);
|
||||
if (null != ret) {
|
||||
sdkProperties.put(key, ret);
|
||||
} else {
|
||||
if (null == sdkProperties.getProperty(key) && value != null) {
|
||||
sdkProperties.put(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured security level. The value determines the elliptic curve used to generate keys.
|
||||
*
|
||||
* @return the security level.
|
||||
*/
|
||||
public int getSecurityLevel() {
|
||||
|
||||
return Integer.parseInt(getProperty(SECURITY_LEVEL));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured security provider.
|
||||
* This is the security provider used for the default SDK crypto suite factory.
|
||||
*
|
||||
* @return the security provider.
|
||||
*/
|
||||
public String getSecurityProviderClassName() {
|
||||
return getProperty(SECURITY_PROVIDER_CLASS_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the configured hash algorithm, used for digital signatures.
|
||||
*
|
||||
* @return the hash algorithm name.
|
||||
*/
|
||||
public String getHashAlgorithm() {
|
||||
return getProperty(HASH_ALGORITHM);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The default ssl provider for grpc connection
|
||||
*
|
||||
* @return The default ssl provider for grpc connection
|
||||
*/
|
||||
public String getDefaultSSLProvider() {
|
||||
return getProperty(CONN_SSL_PROVIDER);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The default ssl negotiation type
|
||||
*
|
||||
* @return The default ssl negotiation type
|
||||
*/
|
||||
|
||||
public String getDefaultSSLNegotiationType() {
|
||||
return getProperty(CONN_SSL_NEGTYPE);
|
||||
|
||||
}
|
||||
|
||||
private Map<Integer, String> curveMapping = null;
|
||||
|
||||
/**
|
||||
* Get a mapping from strength to curve desired.
|
||||
*
|
||||
* @return mapping from strength to curve name to use.
|
||||
*/
|
||||
public Map<Integer, String> getSecurityCurveMapping() {
|
||||
|
||||
if (curveMapping == null) {
|
||||
|
||||
curveMapping = parseSecurityCurveMappings(getProperty(SECURITY_CURVE_MAPPING));
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(curveMapping);
|
||||
}
|
||||
|
||||
public static Map<Integer, String> parseSecurityCurveMappings(final String property) {
|
||||
Map<Integer, String> lcurveMapping = new HashMap<>(8);
|
||||
|
||||
if (property != null && !property.isEmpty()) { //empty will be caught later.
|
||||
|
||||
String[] cmaps = property.split("[ \t]*:[ \t]*");
|
||||
for (String mape : cmaps) {
|
||||
|
||||
String[] ep = mape.split("[ \t]*=[ \t]*");
|
||||
if (ep.length != 2) {
|
||||
logger.warn(format("Bad curve mapping for %s in property %s", mape, SECURITY_CURVE_MAPPING));
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
int parseInt = Integer.parseInt(ep[0]);
|
||||
lcurveMapping.put(parseInt, ep[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn(format("Bad curve mapping. Integer needed for strength %s for %s in property %s",
|
||||
ep[0], mape, SECURITY_CURVE_MAPPING));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return lcurveMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timeout for a single proposal request to endorser.
|
||||
*
|
||||
* @return the timeout in milliseconds.
|
||||
*/
|
||||
public long getProposalWaitTime() {
|
||||
return Long.parseLong(getProperty(PROPOSAL_WAIT_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured time to wait for genesis block.
|
||||
*
|
||||
* @return time in milliseconds.
|
||||
*/
|
||||
public long getGenesisBlockWaitTime() {
|
||||
return Long.parseLong(getProperty(GENESISBLOCK_WAIT_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Time to wait for channel to be configured.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getChannelConfigWaitTime() {
|
||||
return Long.parseLong(getProperty(CHANNEL_CONFIG_WAIT_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Time to wait before retrying an operation.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getOrdererRetryWaitTime() {
|
||||
return Long.parseLong(getProperty(ORDERER_RETRY_WAIT_TIME));
|
||||
}
|
||||
|
||||
public long getOrdererWaitTime() {
|
||||
return Long.parseLong(getProperty(ORDERER_WAIT_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* getPeerEventRegistrationWaitTime
|
||||
*
|
||||
* @return time in milliseconds to wait for peer eventing service to wait for event registration
|
||||
*/
|
||||
public long getPeerEventRegistrationWaitTime() {
|
||||
return Long.parseLong(getProperty(PEER_EVENT_REGISTRATION_WAIT_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* getPeerEventRegistrationWaitTime
|
||||
*
|
||||
* @return time in milliseconds to wait for peer eventing service to wait for event registration
|
||||
*/
|
||||
public long getPeerRetryWaitTime() {
|
||||
return Long.parseLong(getProperty(PEER_EVENT_RETRY_WAIT_TIME));
|
||||
}
|
||||
|
||||
public long getPeerEventReconnectionWarningRate() {
|
||||
return Long.parseLong(getProperty(PEER_EVENT_RECONNECTION_WARNING_RATE));
|
||||
}
|
||||
|
||||
/**
|
||||
* How often serviced discovery is preformed in seconds.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getServiceDiscoveryFreqSeconds() {
|
||||
return Integer.parseInt(getProperty(SERVICE_DISCOVER_FREQ_SECONDS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Time to wait for service discovery to complete.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getServiceDiscoveryWaitTime() {
|
||||
return Integer.parseInt(getProperty(SERVICE_DISCOVER_WAIT_TIME));
|
||||
}
|
||||
|
||||
public boolean discoverAsLocalhost() {
|
||||
return Boolean.parseBoolean(getProperty(SERVICE_DISCOVER_AS_LOCALHOST));
|
||||
}
|
||||
|
||||
public String getAsymmetricKeyType() {
|
||||
return getProperty(ASYMMETRIC_KEY_TYPE);
|
||||
}
|
||||
|
||||
public String getCertificateFormat() {
|
||||
return getProperty(CERTIFICATE_FORMAT);
|
||||
}
|
||||
|
||||
public String getSignatureAlgorithm() {
|
||||
return getProperty(SIGNATURE_ALGORITHM);
|
||||
}
|
||||
|
||||
public String getDefaultCryptoSuiteFactory() {
|
||||
return getProperty(DEFAULT_CRYPTO_SUITE_FACTORY);
|
||||
}
|
||||
|
||||
public int maxLogStringLength() {
|
||||
return Integer.parseInt(getProperty(MAX_LOG_STRING_LENGTH));
|
||||
}
|
||||
|
||||
/**
|
||||
* getProposalConsistencyValidation determine if validation of the proposals should
|
||||
* be done before sending to the orderer.
|
||||
*
|
||||
* @return if true proposals will be checked they are consistent with each other before sending to the Orderer
|
||||
*/
|
||||
|
||||
public boolean getProposalConsistencyValidation() {
|
||||
return Boolean.parseBoolean(getProperty(PROPOSAL_CONSISTENCY_VALIDATION));
|
||||
|
||||
}
|
||||
|
||||
private int extraLogLevel = -1;
|
||||
|
||||
public boolean extraLogLevel(int val) {
|
||||
if (extraLogLevel == -1) {
|
||||
extraLogLevel = Integer.parseInt(getProperty(EXTRALOGLEVEL));
|
||||
}
|
||||
|
||||
return val <= extraLogLevel;
|
||||
|
||||
}
|
||||
|
||||
DiagnosticFileDumper diagnosticFileDumper = null;
|
||||
|
||||
/**
|
||||
* The directory where diagnostic dumps are to be place, null if none should be done.
|
||||
*
|
||||
* @return The directory where diagnostic dumps are to be place, null if none should be done.
|
||||
*/
|
||||
|
||||
public DiagnosticFileDumper getDiagnosticFileDumper() {
|
||||
|
||||
if (diagnosticFileDumper != null) {
|
||||
return diagnosticFileDumper;
|
||||
}
|
||||
|
||||
String dd = sdkProperties.getProperty(DIAGNOTISTIC_FILE_DIRECTORY);
|
||||
|
||||
if (dd != null) {
|
||||
|
||||
diagnosticFileDumper = DiagnosticFileDumper.configInstance(new File(dd));
|
||||
|
||||
}
|
||||
|
||||
return diagnosticFileDumper;
|
||||
}
|
||||
|
||||
/**
|
||||
* This does NOT trigger futures time out and must be kept WELL above any expected future timeout
|
||||
* for transactions sent to the Orderer
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getTransactionListenerCleanUpTimeout() {
|
||||
return Long.parseLong(getProperty(TRANSACTION_CLEANUP_UP_TIMEOUT_WAIT_TIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set
|
||||
*
|
||||
* @return The number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set
|
||||
*/
|
||||
|
||||
public int getClientThreadExecutorCorePoolSize() {
|
||||
return Integer.parseInt(getProperty(CLIENT_THREAD_EXECUTOR_COREPOOLSIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* maximumPoolSize the maximum number of threads to allow in the pool
|
||||
*
|
||||
* @return maximumPoolSize the maximum number of threads to allow in the pool
|
||||
*/
|
||||
public int getClientThreadExecutorMaxiumPoolSize() {
|
||||
return Integer.parseInt(getProperty(CLIENT_THREAD_EXECUTOR_MAXIMUMPOOLSIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* keepAliveTime when the number of threads is greater than
|
||||
* the core, this is the maximum time that excess idle threads
|
||||
* will wait for new tasks before terminating.
|
||||
*
|
||||
* @return The keep alive time.
|
||||
*/
|
||||
|
||||
public long getClientThreadExecutorKeepAliveTime() {
|
||||
return Long.parseLong(getProperty(CLIENT_THREAD_EXECUTOR_KEEPALIVETIME));
|
||||
}
|
||||
|
||||
/**
|
||||
* the time unit for the argument
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
public TimeUnit getClientThreadExecutorKeepAliveTimeUnit() {
|
||||
|
||||
return TimeUnit.valueOf(getProperty(CLIENT_THREAD_EXECUTOR_KEEPALIVETIMEUNIT));
|
||||
}
|
||||
|
||||
/**
|
||||
* The default chaincode Endorsement policy plugin
|
||||
* <p>
|
||||
* This should never need setting
|
||||
*
|
||||
* @return The default chaincode Endorsement policy plugin
|
||||
*/
|
||||
|
||||
public String getDefaultChaincodeEndorsementPlugin() {
|
||||
return getProperty(LIFECYCLE_CHAINCODE_ENDORSEMENT_PLUGIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default chaincode validation plugin
|
||||
* This should never need setting.
|
||||
*
|
||||
* @return The default chaincode validation plugin
|
||||
*/
|
||||
public String getDefaultChaincodeValidationPlugin() {
|
||||
return getProperty(LIFECYCLE_CHAINCODE_VALIDATION_PLUGIN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether require init method in chaincode to be run.
|
||||
* The default will return null which will not set the Fabric protobuf value which then sets false. False is the Fabric
|
||||
* default.
|
||||
*
|
||||
* @return The default setting for initRequired in chaincode approve for my org and commit chaincode definition.
|
||||
*/
|
||||
public Boolean getLifecycleInitRequiredDefault() {
|
||||
|
||||
String property = getProperty(LIFECYCLE_INITREQUIREDDEFAULT);
|
||||
if (property != null) {
|
||||
|
||||
return Boolean.parseBoolean(property);
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2016,2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.helper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.AsynchronousFileChannel;
|
||||
import java.nio.channels.CompletionHandler;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Dumps files for diagnostic purposes
|
||||
*/
|
||||
|
||||
public class DiagnosticFileDumper implements Runnable {
|
||||
|
||||
private final File directory;
|
||||
private final String dirAbsolutePath;
|
||||
private final String pid;
|
||||
// private static final Log logger = LogFactory.getLog(DiagnosticFileDumper.class);
|
||||
private static Thread thread;
|
||||
private final BlockingQueue<QueEntry> queEntries = new LinkedBlockingQueue<>();
|
||||
|
||||
private static DiagnosticFileDumper singleInstance = null;
|
||||
private static final AtomicInteger counter = new AtomicInteger(0);
|
||||
|
||||
private DiagnosticFileDumper(File directory) {
|
||||
|
||||
this.directory = directory;
|
||||
this.dirAbsolutePath = directory == null ? null : directory.getAbsolutePath();
|
||||
this.pid = getPID() + "";
|
||||
|
||||
}
|
||||
|
||||
static DiagnosticFileDumper configInstance(File directory) {
|
||||
|
||||
if (singleInstance == null) {
|
||||
singleInstance = new DiagnosticFileDumper(directory);
|
||||
thread = new Thread(singleInstance);
|
||||
thread.setName("DiagnosticFileDumper");
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
|
||||
}
|
||||
|
||||
return singleInstance;
|
||||
|
||||
}
|
||||
|
||||
public String createDiagnosticProtobufFile(byte[] byteString) {
|
||||
|
||||
return createDiagnosticFile(byteString, "protobuf_", "proto");
|
||||
|
||||
}
|
||||
|
||||
private boolean cantWrite() {
|
||||
return null == directory || !directory.exists() || !directory.isDirectory() || !directory.canWrite();
|
||||
}
|
||||
|
||||
public String createDiagnosticFile(byte[] bytes) {
|
||||
|
||||
return createDiagnosticFile(bytes, null, null);
|
||||
|
||||
}
|
||||
|
||||
public String createDiagnosticTarFile(byte[] bytes) {
|
||||
|
||||
return createDiagnosticFile(bytes, null, "tgz");
|
||||
|
||||
}
|
||||
|
||||
public String createDiagnosticFile(String msg) {
|
||||
|
||||
return createDiagnosticFile(msg.getBytes(StandardCharsets.UTF_8), null, null);
|
||||
|
||||
}
|
||||
|
||||
public String createDiagnosticFile(byte[] bytes, String prefix, String ext) {
|
||||
String fileName = "";
|
||||
if (cantWrite()) {
|
||||
return "Missing dump directory or can not write: " + (dirAbsolutePath);
|
||||
}
|
||||
if (null != bytes) {
|
||||
if (null == prefix) {
|
||||
prefix = "diagnostic_";
|
||||
}
|
||||
if (null == ext) {
|
||||
ext = "bin";
|
||||
}
|
||||
|
||||
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss_SSS");
|
||||
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
fileName = prefix + dateFormatGmt.format(new Date()) + "P" + pid + "_" + Thread.currentThread().getId()
|
||||
+ "_" + counter.addAndGet(1) + "." + ext;
|
||||
fileName = fileName.replaceAll("\\:", "-"); // colon is bad for windows.
|
||||
|
||||
new QueEntry(fileName, bytes); //Add to Que let process by async thread.
|
||||
|
||||
}
|
||||
return fileName;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
while (true) {
|
||||
|
||||
try {
|
||||
final LinkedList<QueEntry> entries = new LinkedList<>();
|
||||
|
||||
entries.add(this.queEntries.take()); // wait on one.
|
||||
this.queEntries.drainTo(entries); //got one, see if there are more.
|
||||
|
||||
if (cantWrite()) {
|
||||
return; //IF the directory is missing just assume user does not want diagnostic files created anymore.
|
||||
}
|
||||
|
||||
entries.forEach(queEntry -> {
|
||||
|
||||
try {
|
||||
final AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get(dirAbsolutePath, queEntry.fileName),
|
||||
StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
|
||||
channel.write(ByteBuffer.wrap(queEntry.dataBytes), 0, null, new CompletionHandler<Integer, Object>() {
|
||||
@Override
|
||||
public void completed(Integer result, Object attachment) {
|
||||
try {
|
||||
channel.close();
|
||||
} catch (IOException e) {
|
||||
//best effort
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable exc, Object attachment) {
|
||||
|
||||
try {
|
||||
channel.close();
|
||||
} catch (IOException e) {
|
||||
//best effort.
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
} catch (IOException e) {
|
||||
//best effort.
|
||||
}
|
||||
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
// best effort
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class QueEntry {
|
||||
final String fileName;
|
||||
final byte[] dataBytes;
|
||||
|
||||
QueEntry(String fileName, byte[] dataBytes) {
|
||||
this.fileName = fileName;
|
||||
this.dataBytes = dataBytes;
|
||||
|
||||
queEntries.add(this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static long getPID() {
|
||||
String processName =
|
||||
java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
|
||||
return Long.parseLong(processName.split("@")[0]);
|
||||
}
|
||||
|
||||
}
|
@ -1,409 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.helper;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Timestamp;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA3Digest;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Instant;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.apache.commons.codec.binary.Hex.encodeHexString;
|
||||
|
||||
public final class Utils {
|
||||
private static final Log logger = LogFactory.getLog(Utils.class);
|
||||
|
||||
private static final boolean TRACE_ENABED = logger.isTraceEnabled();
|
||||
private static final Config config = Config.getConfig();
|
||||
private static final int MAX_LOG_STRING_LENGTH = config.maxLogStringLength();
|
||||
|
||||
/**
|
||||
* Generate parameter hash for the given chaincode path,func and args
|
||||
*
|
||||
* @param path Chaincode path
|
||||
* @param func Chaincode function name
|
||||
* @param args List of arguments
|
||||
* @return hash of path, func and args
|
||||
*/
|
||||
public static String generateParameterHash(String path, String func, List<String> args) {
|
||||
logger.debug(format("GenerateParameterHash : path=%s, func=%s, args=%s", path, func, args));
|
||||
|
||||
// Append the arguments
|
||||
StringBuilder param = new StringBuilder(path);
|
||||
param.append(func);
|
||||
args.forEach(param::append);
|
||||
|
||||
// Compute the hash
|
||||
|
||||
return Hex.toHexString(hash(param.toString().getBytes(UTF_8), new SHA3Digest()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate hash of a chaincode directory
|
||||
*
|
||||
* @param rootDir Root directory
|
||||
* @param chaincodeDir Channel code directory
|
||||
* @param hash Previous hash (if any)
|
||||
* @return hash of the directory
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String generateDirectoryHash(String rootDir, String chaincodeDir, String hash) throws IOException {
|
||||
// Generate the project directory
|
||||
Path projectPath;
|
||||
if (rootDir == null) {
|
||||
projectPath = Paths.get(chaincodeDir);
|
||||
} else {
|
||||
projectPath = Paths.get(rootDir, chaincodeDir);
|
||||
}
|
||||
|
||||
File dir = projectPath.toFile();
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
throw new IOException(format("The chaincode path \"%s\" is invalid", projectPath));
|
||||
}
|
||||
|
||||
StringBuilder hashBuilder = new StringBuilder(hash);
|
||||
Files.walk(projectPath)
|
||||
.sorted(Comparator.naturalOrder())
|
||||
.filter(Files::isRegularFile)
|
||||
.map(Path::toFile)
|
||||
.forEach(file -> {
|
||||
try {
|
||||
byte[] buf = readFile(file);
|
||||
byte[] toHash = Arrays.concatenate(buf, hashBuilder.toString().getBytes(UTF_8));
|
||||
hashBuilder.setLength(0);
|
||||
hashBuilder.append(Hex.toHexString(hash(toHash, new SHA3Digest())));
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(format("Error while reading file %s", file.getAbsolutePath()), ex);
|
||||
}
|
||||
});
|
||||
|
||||
// If original hash and final hash are the same, it indicates that no new contents were found
|
||||
if (hashBuilder.toString().equals(hash)) {
|
||||
throw new IOException(format("The chaincode directory \"%s\" has no files", projectPath));
|
||||
}
|
||||
return hashBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress the contents of given directory using Tar and Gzip to an in-memory byte array.
|
||||
*
|
||||
* @param sourceDirectory the source directory.
|
||||
* @param pathPrefix a path to be prepended to every file name in the .tar.gz output, or {@code null} if no prefix is required.
|
||||
* @param chaincodeMetaInf
|
||||
* @return the compressed directory contents.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static byte[] generateTarGz(File sourceDirectory, String pathPrefix, File chaincodeMetaInf) throws IOException {
|
||||
logger.trace(format("generateTarGz: sourceDirectory: %s, pathPrefix: %s, chaincodeMetaInf: %s",
|
||||
sourceDirectory == null ? "null" : sourceDirectory.getAbsolutePath(), pathPrefix,
|
||||
chaincodeMetaInf == null ? "null" : chaincodeMetaInf.getAbsolutePath()));
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(500000);
|
||||
|
||||
String sourcePath = sourceDirectory.getAbsolutePath();
|
||||
|
||||
// try (TarArchiveOutputStream archiveOutputStream = new TarArchiveOutputStream(new GzipCompressorOutputStream(bos))) {
|
||||
// archiveOutputStream.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);
|
||||
//
|
||||
// Collection<File> childrenFiles = org.apache.commons.io.FileUtils.listFiles(sourceDirectory, null, true);
|
||||
//
|
||||
// ArchiveEntry archiveEntry;
|
||||
// for (File childFile : childrenFiles) {
|
||||
// String childPath = childFile.getAbsolutePath();
|
||||
// String relativePath = childPath.substring((sourcePath.length() + 1));
|
||||
//
|
||||
// if (pathPrefix != null) {
|
||||
// relativePath = Utils.combinePaths(pathPrefix, relativePath);
|
||||
// }
|
||||
//
|
||||
// relativePath = FilenameUtils.separatorsToUnix(relativePath);
|
||||
//
|
||||
// if (TRACE_ENABED) {
|
||||
// logger.trace(format("generateTarGz: Adding '%s' entry from source '%s' to archive.", relativePath, childFile.getAbsolutePath()));
|
||||
// }
|
||||
//
|
||||
// archiveEntry = new TarArchiveEntry(childFile, relativePath);
|
||||
// archiveOutputStream.putArchiveEntry(archiveEntry);
|
||||
//
|
||||
// try (FileInputStream fileInputStream = new FileInputStream(childFile)) {
|
||||
// IOUtils.copy(fileInputStream, archiveOutputStream);
|
||||
// } finally {
|
||||
// archiveOutputStream.closeArchiveEntry();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// if (null != chaincodeMetaInf) {
|
||||
// childrenFiles = org.apache.commons.io.FileUtils.listFiles(chaincodeMetaInf, null, true);
|
||||
//
|
||||
// final URI metabase = chaincodeMetaInf.toURI();
|
||||
//
|
||||
// for (File childFile : childrenFiles) {
|
||||
//
|
||||
// final String relativePath = Paths.get("META-INF", metabase.relativize(childFile.toURI()).getPath()).toString();
|
||||
//
|
||||
// if (TRACE_ENABED) {
|
||||
// logger.trace(format("generateTarGz: Adding '%s' entry from source '%s' to archive.", relativePath, childFile.getAbsolutePath()));
|
||||
// }
|
||||
//
|
||||
// archiveEntry = new TarArchiveEntry(childFile, relativePath);
|
||||
// archiveOutputStream.putArchiveEntry(archiveEntry);
|
||||
//
|
||||
// try (FileInputStream fileInputStream = new FileInputStream(childFile)) {
|
||||
// IOUtils.copy(fileInputStream, archiveOutputStream);
|
||||
// } finally {
|
||||
// archiveOutputStream.closeArchiveEntry();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the contents a file.
|
||||
*
|
||||
* @param input source file to read.
|
||||
* @return contents of the file.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static byte[] readFile(File input) throws IOException {
|
||||
return Files.readAllBytes(Paths.get(input.getAbsolutePath()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a v4 UUID
|
||||
*
|
||||
* @return String representation of {@link UUID}
|
||||
*/
|
||||
public static String generateUUID() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Timestamp} instance based on the current time
|
||||
*
|
||||
* @return timestamp
|
||||
*/
|
||||
public static Timestamp generateTimestamp() {
|
||||
Instant time = Instant.now();
|
||||
return Timestamp.newBuilder().setSeconds(time.getEpochSecond())
|
||||
.setNanos(time.getNano()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file or directory
|
||||
*
|
||||
* @param file {@link File} representing file or directory
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void deleteFileOrDirectory(File file) throws IOException {
|
||||
if (file.exists()) {
|
||||
if (file.isDirectory()) {
|
||||
Path rootPath = Paths.get(file.getAbsolutePath());
|
||||
|
||||
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
.forEach(File::delete);
|
||||
} else {
|
||||
file.delete();
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("File or directory does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate hash of the given input using the given Digest.
|
||||
*
|
||||
* @param input input data.
|
||||
* @param digest the digest to use for hashing
|
||||
* @return hashed data.
|
||||
*/
|
||||
public static byte[] hash(byte[] input, Digest digest) {
|
||||
byte[] retValue = new byte[digest.getDigestSize()];
|
||||
digest.update(input, 0, input.length);
|
||||
digest.doFinal(retValue, 0);
|
||||
return retValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine two or more paths
|
||||
*
|
||||
* @param first parent directory path
|
||||
* @param other children
|
||||
* @return combined path
|
||||
*/
|
||||
public static String combinePaths(String first, String... other) {
|
||||
return Paths.get(first, other).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file from classpath
|
||||
*
|
||||
* @param fileName
|
||||
* @return byte[] data
|
||||
* @throws IOException
|
||||
*/
|
||||
public static byte[] readFileFromClasspath(String fileName) throws IOException {
|
||||
try (InputStream is = Utils.class.getClassLoader().getResourceAsStream(fileName)) {
|
||||
return IOUtils.toByteArray(is);
|
||||
}
|
||||
}
|
||||
|
||||
public static Properties parseGrpcUrl(String url) {
|
||||
if (isNullOrEmpty(url)) {
|
||||
throw new RuntimeException("URL cannot be null or empty");
|
||||
}
|
||||
|
||||
Properties props = new Properties();
|
||||
Pattern p = Pattern.compile("([^:]+)[:]//([^:]+)[:]([0-9]+)", Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = p.matcher(url);
|
||||
if (m.matches()) {
|
||||
props.setProperty("protocol", m.group(1));
|
||||
props.setProperty("host", m.group(2));
|
||||
props.setProperty("port", m.group(3));
|
||||
|
||||
String protocol = props.getProperty("protocol");
|
||||
if (!"grpc".equals(protocol) && !"grpcs".equals(protocol)) {
|
||||
throw new RuntimeException(format("Invalid protocol expected grpc or grpcs and found %s.", protocol));
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("URL must be of the format protocol://host:port. Found: '" + url + "'");
|
||||
}
|
||||
|
||||
// TODO: allow all possible formats of the URL
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the strings Grpc url is valid
|
||||
*
|
||||
* @param url
|
||||
* @return Return the io.seata.core.exception that indicates the error or null if ok.
|
||||
*/
|
||||
public static Exception checkGrpcUrl(String url) {
|
||||
try {
|
||||
|
||||
parseGrpcUrl(url);
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is null or empty.
|
||||
*
|
||||
* @param url the string to test.
|
||||
* @return {@code true} if the string is null or empty; otherwise {@code false}.
|
||||
*/
|
||||
public static boolean isNullOrEmpty(String url) {
|
||||
return url == null || url.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes logging strings which can be long or with unprintable characters be logged and trimmed.
|
||||
*
|
||||
* @param string Unsafe string too long
|
||||
* @return returns a string which does not have unprintable characters and trimmed in length.
|
||||
*/
|
||||
public static String logString(final String string) {
|
||||
if (string == null || string.length() == 0) {
|
||||
return string;
|
||||
}
|
||||
|
||||
String ret = string.replaceAll("[^\\p{Print}]", "?");
|
||||
|
||||
ret = ret.substring(0, Math.min(ret.length(), MAX_LOG_STRING_LENGTH)) + (ret.length() > MAX_LOG_STRING_LENGTH ? "..." : "");
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
private static final int NONONCE_LENGTH = 24;
|
||||
|
||||
private static final SecureRandom RANDOM = new SecureRandom();
|
||||
|
||||
public static byte[] generateNonce() {
|
||||
|
||||
byte[] values = new byte[NONONCE_LENGTH];
|
||||
RANDOM.nextBytes(values);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static String toHexString(ByteString byteString) {
|
||||
if (byteString == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return encodeHexString(byteString.toByteArray());
|
||||
|
||||
}
|
||||
|
||||
public static String toHexString(byte[] bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return encodeHexString(bytes);
|
||||
|
||||
}
|
||||
|
||||
public static String toHexString(String bytes) {
|
||||
if (bytes == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return encodeHexString(bytes.getBytes(UTF_8));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation.
|
||||
*/
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
}
|
@ -1,976 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016, 2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.security;
|
||||
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.InvalidArgumentException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.helper.Config;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.helper.DiagnosticFileDumper;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.bouncycastle.asn1.*;
|
||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA3Digest;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
|
||||
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
|
||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
|
||||
import org.bouncycastle.util.io.pem.PemObject;
|
||||
import org.bouncycastle.util.io.pem.PemReader;
|
||||
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.io.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.*;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import static com.chinaunicom.mall.ebtp.common.crypto.helper.Utils.isNullOrEmpty;
|
||||
import static java.lang.String.format;
|
||||
|
||||
public class CryptoPrimitives implements CryptoSuite {
|
||||
private static final Log logger = LogFactory.getLog(CryptoPrimitives.class);
|
||||
private static final Config config = Config.getConfig();
|
||||
private static final boolean IS_TRACE_LEVEL = logger.isTraceEnabled();
|
||||
|
||||
private static final DiagnosticFileDumper diagnosticFileDumper = IS_TRACE_LEVEL
|
||||
? config.getDiagnosticFileDumper() : null;
|
||||
|
||||
private String curveName;
|
||||
private CertificateFactory cf;
|
||||
private Provider SECURITY_PROVIDER;
|
||||
private String hashAlgorithm = config.getHashAlgorithm();
|
||||
private int securityLevel = config.getSecurityLevel();
|
||||
private String CERTIFICATE_FORMAT = config.getCertificateFormat();
|
||||
private String DEFAULT_SIGNATURE_ALGORITHM = config.getSignatureAlgorithm();
|
||||
|
||||
private Map<Integer, String> securityCurveMapping = config.getSecurityCurveMapping();
|
||||
|
||||
// Following configuration settings are hardcoded as they don't deal with any interactions with Fabric MSP and BCCSP components
|
||||
// If you wish to make these customizable, follow the logic from setProperties();
|
||||
//TODO May need this for TCERTS ?
|
||||
// private String ASYMMETRIC_KEY_TYPE = "EC";
|
||||
// private String KEY_AGREEMENT_ALGORITHM = "ECDH";
|
||||
// private String SYMMETRIC_KEY_TYPE = "AES";
|
||||
// private int SYMMETRIC_KEY_BYTE_COUNT = 32;
|
||||
// private String SYMMETRIC_ALGORITHM = "AES/CFB/NoPadding";
|
||||
// private int MAC_KEY_BYTE_COUNT = 32;
|
||||
|
||||
public CryptoPrimitives() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||
String securityProviderClassName = config.getSecurityProviderClassName();
|
||||
|
||||
SECURITY_PROVIDER = setUpExplicitProvider(securityProviderClassName);
|
||||
|
||||
//Decided TO NOT do this as it can have affects over the whole JVM and could have
|
||||
// unexpected results. The embedding application can easily do this!
|
||||
// Leaving this here as a warning.
|
||||
// Security.insertProviderAt(SECURITY_PROVIDER, 1); // 1 is top not 0 :)
|
||||
}
|
||||
|
||||
Provider setUpExplicitProvider(String securityProviderClassName) throws InstantiationException, ClassNotFoundException, IllegalAccessException {
|
||||
if (null == securityProviderClassName) {
|
||||
throw new InstantiationException(format("Security provider class name property (%s) set to null ", Config.SECURITY_PROVIDER_CLASS_NAME));
|
||||
}
|
||||
|
||||
if (CryptoSuiteFactory.DEFAULT_JDK_PROVIDER.equals(securityProviderClassName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> aClass = Class.forName(securityProviderClassName);
|
||||
if (null == aClass) {
|
||||
throw new InstantiationException(format("Getting class for security provider %s returned null ", securityProviderClassName));
|
||||
}
|
||||
if (!Provider.class.isAssignableFrom(aClass)) {
|
||||
throw new InstantiationException(format("Class for security provider %s is not a Java security provider", aClass.getName()));
|
||||
}
|
||||
Provider securityProvider = (Provider) aClass.newInstance();
|
||||
if (securityProvider == null) {
|
||||
throw new InstantiationException(format("Creating instance of security %s returned null ", aClass.getName()));
|
||||
}
|
||||
return securityProvider;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * sets the signature algorithm used for signing/verifying.
|
||||
// *
|
||||
// * @param sigAlg the name of the signature algorithm. See the list of valid names in the JCA Standard Algorithm Name documentation
|
||||
// */
|
||||
// public void setSignatureAlgorithm(String sigAlg) {
|
||||
// this.DEFAULT_SIGNATURE_ALGORITHM = sigAlg;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * returns the signature algorithm used by this instance of CryptoPrimitives.
|
||||
// * Note that fabric and fabric-ca have not yet standardized on which algorithms are supported.
|
||||
// * While that plays out, CryptoPrimitives will try the algorithm specified in the certificate and
|
||||
// * the default SHA256withECDSA that's currently hardcoded for fabric and fabric-ca
|
||||
// *
|
||||
// * @return the name of the signature algorithm
|
||||
// */
|
||||
// public String getSignatureAlgorithm() {
|
||||
// return this.DEFAULT_SIGNATURE_ALGORITHM;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public Certificate bytesToCertificate(byte[] certBytes) throws CryptoException {
|
||||
if (certBytes == null || certBytes.length == 0) {
|
||||
throw new CryptoException("bytesToCertificate: input null or zero length");
|
||||
}
|
||||
|
||||
return getX509Certificate(certBytes);
|
||||
// X509Certificate certificate;
|
||||
// try {
|
||||
// BufferedInputStream pem = new BufferedInputStream(new ByteArrayInputStream(certBytes));
|
||||
// CertificateFactory certFactory = CertificateFactory.getInstance(CERTIFICATE_FORMAT);
|
||||
// certificate = (X509Certificate) certFactory.generateCertificate(pem);
|
||||
// } catch (CertificateException e) {
|
||||
// String emsg = "Unable to converts byte array to certificate. error : " + e.getMessage();
|
||||
// logger.error(emsg);
|
||||
// logger.debug("input bytes array :" + new String(certBytes));
|
||||
// throw new CryptoException(emsg, e);
|
||||
// }
|
||||
//
|
||||
// return certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return X509Certificate from pem bytes.
|
||||
* So you may ask why this ? Well some providers (BC) seems to have problems with creating the
|
||||
* X509 cert from bytes so here we go through all available providers till one can convert. :)
|
||||
*
|
||||
* @param pemCertificate
|
||||
* @return
|
||||
*/
|
||||
|
||||
private X509Certificate getX509Certificate(byte[] pemCertificate) throws CryptoException {
|
||||
X509Certificate ret = null;
|
||||
CryptoException rete = null;
|
||||
|
||||
List<Provider> providerList = new LinkedList<>(Arrays.asList(Security.getProviders()));
|
||||
if (SECURITY_PROVIDER != null) { //Add if overridden
|
||||
providerList.add(SECURITY_PROVIDER);
|
||||
}
|
||||
try {
|
||||
providerList.add(BouncyCastleProvider.class.newInstance()); // bouncy castle is there always.
|
||||
} catch (Exception e) {
|
||||
logger.warn(e);
|
||||
|
||||
}
|
||||
for (Provider provider : providerList) {
|
||||
try {
|
||||
if (null == provider) {
|
||||
continue;
|
||||
}
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance(CERTIFICATE_FORMAT, provider);
|
||||
if (null != certFactory) {
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(pemCertificate)) {
|
||||
Certificate certificate = certFactory.generateCertificate(bis);
|
||||
|
||||
if (certificate instanceof X509Certificate) {
|
||||
ret = (X509Certificate) certificate;
|
||||
rete = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
rete = new CryptoException(e.getMessage(), e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (null != rete) {
|
||||
|
||||
throw rete;
|
||||
|
||||
}
|
||||
|
||||
if (ret == null) {
|
||||
|
||||
logger.error("Could not convert pem bytes");
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return PrivateKey from pem bytes.
|
||||
*
|
||||
* @param pemKey pem-encoded private key
|
||||
* @return
|
||||
*/
|
||||
public PrivateKey bytesToPrivateKey(byte[] pemKey) throws CryptoException {
|
||||
PrivateKey pk;
|
||||
|
||||
try {
|
||||
PemReader pr = new PemReader(new StringReader(new String(pemKey)));
|
||||
PemObject po = pr.readPemObject();
|
||||
PEMParser pem = new PEMParser(new StringReader(new String(pemKey)));
|
||||
|
||||
if (po.getType().equals("PRIVATE KEY")) {
|
||||
pk = new JcaPEMKeyConverter().getPrivateKey((PrivateKeyInfo) pem.readObject());
|
||||
} else {
|
||||
logger.trace("Found private key with type " + po.getType());
|
||||
PEMKeyPair kp = (PEMKeyPair) pem.readObject();
|
||||
pk = new JcaPEMKeyConverter().getPrivateKey(kp.getPrivateKeyInfo());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException("Failed to convert private key bytes", e);
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(byte[] pemCertificate, String signatureAlgorithm, byte[] signature, byte[] plainText) throws CryptoException {
|
||||
boolean isVerified = false;
|
||||
|
||||
if (plainText == null || signature == null || pemCertificate == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.extraLogLevel(10)) {
|
||||
if (null != diagnosticFileDumper) {
|
||||
String message = "plaintext in hex: " + DatatypeConverter.printHexBinary(plainText) + '\n' +
|
||||
"signature in hex: " + DatatypeConverter.printHexBinary(signature) + '\n' +
|
||||
"PEM cert in hex: " + DatatypeConverter.printHexBinary(pemCertificate);
|
||||
logger.trace("verify : " +
|
||||
diagnosticFileDumper.createDiagnosticFile(message));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
X509Certificate certificate = getX509Certificate(pemCertificate);
|
||||
|
||||
if (certificate != null) {
|
||||
|
||||
//isVerified = validateCertificate(certificate);
|
||||
isVerified = true;
|
||||
if (isVerified) { // only proceed if cert is trusted
|
||||
|
||||
Signature sig = Signature.getInstance(signatureAlgorithm);
|
||||
sig.initVerify(certificate);
|
||||
sig.update(plainText);
|
||||
isVerified = sig.verify(signature);
|
||||
}
|
||||
}
|
||||
} catch (InvalidKeyException e) {
|
||||
CryptoException ex = new CryptoException("Cannot verify signature. Error is: "
|
||||
+ e.getMessage() + "\r\nCertificate: "
|
||||
+ DatatypeConverter.printHexBinary(pemCertificate), e);
|
||||
logger.error(ex.getMessage(), ex);
|
||||
throw ex;
|
||||
} catch (NoSuchAlgorithmException | SignatureException e) {
|
||||
CryptoException ex = new CryptoException("Cannot verify. Signature algorithm is invalid. Error is: " + e.getMessage(), e);
|
||||
logger.error(ex.getMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return isVerified;
|
||||
} // verify
|
||||
|
||||
private KeyStore trustStore = null;
|
||||
|
||||
private void createTrustStore() throws CryptoException {
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(null, null);
|
||||
setTrustStore(keyStore);
|
||||
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | InvalidArgumentException e) {
|
||||
throw new CryptoException("Cannot create trust store. Error: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setTrustStore uses the given KeyStore object as the container for trusted
|
||||
* certificates
|
||||
*
|
||||
* @param keyStore the KeyStore which will be used to hold trusted certificates
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private void setTrustStore(KeyStore keyStore) throws InvalidArgumentException {
|
||||
|
||||
if (keyStore == null) {
|
||||
throw new InvalidArgumentException("Need to specify a java.security.KeyStore input parameter");
|
||||
}
|
||||
|
||||
trustStore = keyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* getTrustStore returns the KeyStore object where we keep trusted certificates.
|
||||
* If no trust store has been set, this method will create one.
|
||||
*
|
||||
* @return the trust store as a java.security.KeyStore object
|
||||
* @throws CryptoException
|
||||
* @see KeyStore
|
||||
*/
|
||||
public KeyStore getTrustStore() throws CryptoException {
|
||||
if (trustStore == null) {
|
||||
createTrustStore();
|
||||
}
|
||||
return trustStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* addCACertificateToTrustStore adds a CA cert to the set of certificates used for signature validation
|
||||
*
|
||||
* @param caCertPem an X.509 certificate in PEM format
|
||||
* @param alias an alias associated with the certificate. Used as shorthand for the certificate during crypto operations
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public void addCACertificateToTrustStore(File caCertPem, String alias) throws CryptoException, InvalidArgumentException {
|
||||
|
||||
if (caCertPem == null) {
|
||||
throw new InvalidArgumentException("The certificate cannot be null");
|
||||
}
|
||||
|
||||
if (alias == null || alias.isEmpty()) {
|
||||
throw new InvalidArgumentException("You must assign an alias to a certificate when adding to the trust store");
|
||||
}
|
||||
|
||||
try {
|
||||
try (BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(FileUtils.readFileToByteArray(caCertPem)))) {
|
||||
|
||||
Certificate caCert = cf.generateCertificate(bis);
|
||||
addCACertificateToTrustStore(caCert, alias);
|
||||
}
|
||||
} catch (CertificateException | IOException e) {
|
||||
throw new CryptoException("Unable to add CA certificate to trust store. Error: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* addCACertificatesToTrustStore adds a CA certs in a stream to the trust store used for signature validation
|
||||
*
|
||||
* @param bis an X.509 certificate stream in PEM format in bytes
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public void addCACertificatesToTrustStore(BufferedInputStream bis) throws CryptoException, InvalidArgumentException {
|
||||
|
||||
if (bis == null) {
|
||||
throw new InvalidArgumentException("The certificate stream bis cannot be null");
|
||||
}
|
||||
|
||||
try {
|
||||
final Collection<? extends Certificate> certificates = cf.generateCertificates(bis);
|
||||
for (Certificate certificate : certificates) {
|
||||
addCACertificateToTrustStore(certificate);
|
||||
}
|
||||
|
||||
} catch (CertificateException e) {
|
||||
throw new CryptoException("Unable to add CA certificate to trust store. Error: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
final Set<String> certificateSet = ConcurrentHashMap.newKeySet();
|
||||
|
||||
private void addCACertificateToTrustStore(Certificate certificate) throws InvalidArgumentException, CryptoException {
|
||||
|
||||
String alias;
|
||||
if (certificate instanceof X509Certificate) {
|
||||
alias = ((X509Certificate) certificate).getSerialNumber().toString();
|
||||
} else { // not likely ...
|
||||
alias = Integer.toString(certificate.hashCode());
|
||||
}
|
||||
addCACertificateToTrustStore(certificate, alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* addCACertificateToTrustStore adds a CA cert to the set of certificates used for signature validation
|
||||
*
|
||||
* @param caCert an X.509 certificate
|
||||
* @param alias an alias associated with the certificate. Used as shorthand for the certificate during crypto operations
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
void addCACertificateToTrustStore(Certificate caCert, String alias) throws InvalidArgumentException, CryptoException {
|
||||
|
||||
if (alias == null || alias.isEmpty()) {
|
||||
throw new InvalidArgumentException("You must assign an alias to a certificate when adding to the trust store.");
|
||||
}
|
||||
|
||||
if (caCert == null) {
|
||||
throw new InvalidArgumentException("Certificate cannot be null.");
|
||||
}
|
||||
|
||||
try {
|
||||
if (config.extraLogLevel(10)) {
|
||||
if (null != diagnosticFileDumper) {
|
||||
logger.trace(format("Adding cert to trust store. alias: %s. certificate:", alias) + diagnosticFileDumper.createDiagnosticFile(alias + "cert: " + caCert.toString()));
|
||||
}
|
||||
}
|
||||
synchronized (certificateSet) {
|
||||
if (certificateSet.contains(alias)) {
|
||||
return;
|
||||
}
|
||||
|
||||
getTrustStore().setCertificateEntry(alias, caCert);
|
||||
certificateSet.add(alias);
|
||||
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
String emsg = "Unable to add CA certificate to trust store. Error: " + e.getMessage();
|
||||
logger.error(emsg, e);
|
||||
throw new CryptoException(emsg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCACertificates(Collection<Certificate> certificates) throws CryptoException {
|
||||
if (certificates == null || certificates.size() == 0) {
|
||||
throw new CryptoException("Unable to load CA certificates. List is empty");
|
||||
}
|
||||
|
||||
try {
|
||||
for (Certificate cert : certificates) {
|
||||
|
||||
addCACertificateToTrustStore(cert);
|
||||
}
|
||||
} catch (InvalidArgumentException e) {
|
||||
// Note: This can currently never happen (as cert<>null and alias<>null)
|
||||
throw new CryptoException("Unable to add certificate to trust store. Error: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security.CryptoSuite#loadCACertificatesAsBytes(java.util.Collection)
|
||||
*/
|
||||
@Override
|
||||
public void loadCACertificatesAsBytes(Collection<byte[]> certificatesBytes) throws CryptoException {
|
||||
if (certificatesBytes == null || certificatesBytes.size() == 0) {
|
||||
throw new CryptoException("List of CA certificates is empty. Nothing to load.");
|
||||
}
|
||||
|
||||
ArrayList<Certificate> certList = new ArrayList<>();
|
||||
for (byte[] certBytes : certificatesBytes) {
|
||||
certList.add(bytesToCertificate(certBytes));
|
||||
}
|
||||
loadCACertificates(certList);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a CA certificate with a private key and password.
|
||||
*
|
||||
* @param clientKey the private key bytes input stream. Cannot be null.
|
||||
* @param clientCert the client certificate bytes input stream. Cannot be null.
|
||||
* @param clientKeyPassword the password as a String. Can be null.
|
||||
*/
|
||||
public void addClientCACertificateToTrustStore(byte[] clientKey, byte[] clientCert, String clientKeyPassword) throws CryptoException, IllegalArgumentException {
|
||||
if (clientKey == null) {
|
||||
throw new IllegalArgumentException("Client key byte input stream is required.");
|
||||
}
|
||||
if (clientCert == null) {
|
||||
throw new IllegalArgumentException("Client certificate byte input stream is required.");
|
||||
}
|
||||
try {
|
||||
Certificate tlsClientCertificate = bytesToCertificate(clientCert);
|
||||
|
||||
String alias;
|
||||
if (tlsClientCertificate instanceof X509Certificate) {
|
||||
alias = ((X509Certificate) tlsClientCertificate).getSerialNumber().toString();
|
||||
} else { // not likely ...
|
||||
alias = Integer.toString(tlsClientCertificate.hashCode());
|
||||
}
|
||||
char[] password = clientKeyPassword == null ? new char[0] : clientKeyPassword.toCharArray();
|
||||
|
||||
getTrustStore().setKeyEntry(alias, bytesToPrivateKey(clientKey), password, new Certificate[]{tlsClientCertificate});
|
||||
} catch (KeyStoreException e) {
|
||||
throw new CryptoException("Unable to add client CA certificate to trust store.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validateCertificate checks whether the given certificate is trusted. It
|
||||
* checks if the certificate is signed by one of the trusted certs in the
|
||||
* trust store.
|
||||
*
|
||||
* @param certPEM the certificate in PEM format
|
||||
* @return true if the certificate is trusted
|
||||
*/
|
||||
boolean validateCertificate(byte[] certPEM) {
|
||||
|
||||
if (certPEM == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
X509Certificate certificate = getX509Certificate(certPEM);
|
||||
if (null == certificate) {
|
||||
throw new Exception("Certificate transformation returned null");
|
||||
}
|
||||
|
||||
return validateCertificate(certificate);
|
||||
} catch (Exception e) {
|
||||
logger.error("Cannot validate certificate. Error is: " + e.getMessage() + "\r\nCertificate (PEM, hex): "
|
||||
+ DatatypeConverter.printHexBinary(certPEM));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean validateCertificate(Certificate cert) {
|
||||
boolean isValidated;
|
||||
|
||||
if (cert == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
KeyStore keyStore = getTrustStore();
|
||||
|
||||
PKIXParameters parms = new PKIXParameters(keyStore);
|
||||
parms.setRevocationEnabled(false);
|
||||
|
||||
CertPathValidator certValidator = CertPathValidator.getInstance(CertPathValidator.getDefaultType()); // PKIX
|
||||
|
||||
ArrayList<Certificate> start = new ArrayList<>();
|
||||
start.add(cert);
|
||||
CertificateFactory certFactory = CertificateFactory.getInstance(CERTIFICATE_FORMAT);
|
||||
CertPath certPath = certFactory.generateCertPath(start);
|
||||
|
||||
certValidator.validate(certPath, parms);
|
||||
isValidated = true;
|
||||
} catch (KeyStoreException | InvalidAlgorithmParameterException | NoSuchAlgorithmException
|
||||
| CertificateException | CertPathValidatorException | CryptoException e) {
|
||||
logger.error("Cannot validate certificate. Error is: " + e.getMessage() + "\r\nCertificate"
|
||||
+ cert.toString());
|
||||
isValidated = false;
|
||||
}
|
||||
|
||||
return isValidated;
|
||||
} // validateCertificate
|
||||
|
||||
/**
|
||||
* Security Level determines the elliptic curve used in key generation
|
||||
*
|
||||
* @param securityLevel currently 256 or 384
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
void setSecurityLevel(final int securityLevel) throws InvalidArgumentException {
|
||||
logger.trace(format("setSecurityLevel to %d", securityLevel));
|
||||
|
||||
if (securityCurveMapping.isEmpty()) {
|
||||
throw new InvalidArgumentException("Security curve mapping has no entries.");
|
||||
}
|
||||
|
||||
if (!securityCurveMapping.containsKey(securityLevel)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String sp = "";
|
||||
for (int x : securityCurveMapping.keySet()) {
|
||||
sb.append(sp).append(x);
|
||||
|
||||
sp = ", ";
|
||||
|
||||
}
|
||||
throw new InvalidArgumentException(format("Illegal security level: %d. Valid values are: %s", securityLevel, sb.toString()));
|
||||
}
|
||||
|
||||
String lcurveName = securityCurveMapping.get(securityLevel);
|
||||
|
||||
logger.debug(format("Mapped curve strength %d to %s", securityLevel, lcurveName));
|
||||
|
||||
X9ECParameters params = ECNamedCurveTable.getByName(lcurveName);
|
||||
//Check if can match curve name to requested strength.
|
||||
if (params == null) {
|
||||
|
||||
InvalidArgumentException invalidArgumentException = new InvalidArgumentException(
|
||||
format("Curve %s defined for security strength %d was not found.", curveName, securityLevel));
|
||||
|
||||
logger.error(invalidArgumentException);
|
||||
throw invalidArgumentException;
|
||||
|
||||
}
|
||||
|
||||
curveName = lcurveName;
|
||||
this.securityLevel = securityLevel;
|
||||
}
|
||||
|
||||
void setHashAlgorithm(String algorithm) throws InvalidArgumentException {
|
||||
if (isNullOrEmpty(algorithm)
|
||||
|| !("SHA2".equals(algorithm) || "SHA3".equals(algorithm))) {
|
||||
throw new InvalidArgumentException("Illegal Hash function family: "
|
||||
+ algorithm + " - must be either SHA2 or SHA3");
|
||||
}
|
||||
|
||||
hashAlgorithm = algorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyPair keyGen() throws CryptoException {
|
||||
return ecdsaKeyGen();
|
||||
}
|
||||
|
||||
private KeyPair ecdsaKeyGen() throws CryptoException {
|
||||
return generateKey("EC", curveName);
|
||||
}
|
||||
|
||||
private KeyPair generateKey(String encryptionName, String curveName) throws CryptoException {
|
||||
try {
|
||||
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec(curveName);
|
||||
KeyPairGenerator g = SECURITY_PROVIDER == null ? KeyPairGenerator.getInstance(encryptionName) :
|
||||
KeyPairGenerator.getInstance(encryptionName, SECURITY_PROVIDER);
|
||||
g.initialize(ecGenSpec, new SecureRandom());
|
||||
return g.generateKeyPair();
|
||||
} catch (Exception exp) {
|
||||
throw new CryptoException("Unable to generate key pair", exp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an ECDSA signature and returns a two element BigInteger array.
|
||||
*
|
||||
* @param signature ECDSA signature bytes.
|
||||
* @return BigInteger array for the signature's r and s values
|
||||
* @throws Exception
|
||||
*/
|
||||
private static BigInteger[] decodeECDSASignature(byte[] signature) throws Exception {
|
||||
|
||||
try (ByteArrayInputStream inStream = new ByteArrayInputStream(signature)) {
|
||||
ASN1InputStream asnInputStream = new ASN1InputStream(inStream);
|
||||
ASN1Primitive asn1 = asnInputStream.readObject();
|
||||
|
||||
BigInteger[] sigs = new BigInteger[2];
|
||||
int count = 0;
|
||||
if (asn1 instanceof ASN1Sequence) {
|
||||
ASN1Sequence asn1Sequence = (ASN1Sequence) asn1;
|
||||
ASN1Encodable[] asn1Encodables = asn1Sequence.toArray();
|
||||
for (ASN1Encodable asn1Encodable : asn1Encodables) {
|
||||
ASN1Primitive asn1Primitive = asn1Encodable.toASN1Primitive();
|
||||
if (asn1Primitive instanceof ASN1Integer) {
|
||||
ASN1Integer asn1Integer = (ASN1Integer) asn1Primitive;
|
||||
BigInteger integer = asn1Integer.getValue();
|
||||
if (count < 2) {
|
||||
sigs[count] = integer;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count != 2) {
|
||||
throw new CryptoException(format("Invalid ECDSA signature. Expected count of 2 but got: %d. Signature is: %s", count,
|
||||
DatatypeConverter.printHexBinary(signature)));
|
||||
}
|
||||
return sigs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign data with the specified elliptic curve private key.
|
||||
*
|
||||
* @param privateKey elliptic curve private key.
|
||||
* @param data data to sign
|
||||
* @return the signed data.
|
||||
* @throws CryptoException
|
||||
*/
|
||||
private byte[] ecdsaSignToBytes(ECPrivateKey privateKey, byte[] data) throws CryptoException {
|
||||
if (data == null) {
|
||||
throw new CryptoException("Data that to be signed is null.");
|
||||
}
|
||||
if (data.length == 0) {
|
||||
throw new CryptoException("Data to be signed was empty.");
|
||||
}
|
||||
|
||||
try {
|
||||
X9ECParameters params = ECNamedCurveTable.getByName(curveName);
|
||||
BigInteger curveN = params.getN();
|
||||
|
||||
Signature sig = SECURITY_PROVIDER == null ? Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM) :
|
||||
Signature.getInstance(DEFAULT_SIGNATURE_ALGORITHM, SECURITY_PROVIDER);
|
||||
sig.initSign(privateKey);
|
||||
sig.update(data);
|
||||
byte[] signature = sig.sign();
|
||||
|
||||
BigInteger[] sigs = preventMalleability(decodeECDSASignature(signature), curveN);
|
||||
|
||||
try (ByteArrayOutputStream s = new ByteArrayOutputStream()) {
|
||||
|
||||
DERSequenceGenerator seq = new DERSequenceGenerator(s);
|
||||
seq.addObject(new ASN1Integer(sigs[0]));
|
||||
seq.addObject(new ASN1Integer(sigs[1]));
|
||||
seq.close();
|
||||
return s.toByteArray();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException("Could not sign the message using private key", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ClassCastException if the supplied private key is not of type {@link ECPrivateKey}.
|
||||
*/
|
||||
@Override
|
||||
public byte[] sign(PrivateKey key, byte[] data) throws CryptoException {
|
||||
return ecdsaSignToBytes((ECPrivateKey) key, data);
|
||||
}
|
||||
|
||||
private BigInteger[] preventMalleability(BigInteger[] sigs, BigInteger curveN) {
|
||||
BigInteger cmpVal = curveN.divide(BigInteger.valueOf(2L));
|
||||
|
||||
BigInteger sval = sigs[1];
|
||||
|
||||
if (sval.compareTo(cmpVal) > 0) {
|
||||
|
||||
sigs[1] = curveN.subtract(sval);
|
||||
}
|
||||
|
||||
return sigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* generateCertificationRequest
|
||||
*
|
||||
* @param subject The subject to be added to the certificate
|
||||
* @param pair Public private key pair
|
||||
* @return PKCS10CertificationRequest Certificate Signing Request.
|
||||
* @throws OperatorCreationException
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String generateCertificationRequest(String subject, KeyPair pair)
|
||||
throws InvalidArgumentException {
|
||||
|
||||
try {
|
||||
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(
|
||||
new X500Principal("CN=" + subject), pair.getPublic());
|
||||
|
||||
JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withECDSA");
|
||||
|
||||
if (null != SECURITY_PROVIDER) {
|
||||
csBuilder.setProvider(SECURITY_PROVIDER);
|
||||
}
|
||||
ContentSigner signer = csBuilder.build(pair.getPrivate());
|
||||
|
||||
return certificationRequestToPEM(p10Builder.build(signer));
|
||||
} catch (Exception e) {
|
||||
|
||||
logger.error(e);
|
||||
throw new InvalidArgumentException(e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* certificationRequestToPEM - Convert a PKCS10CertificationRequest to PEM
|
||||
* format.
|
||||
*
|
||||
* @param csr The Certificate to convert
|
||||
* @return An equivalent PEM format certificate.
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
private String certificationRequestToPEM(PKCS10CertificationRequest csr) throws IOException {
|
||||
PemObject pemCSR = new PemObject("CERTIFICATE REQUEST", csr.getEncoded());
|
||||
|
||||
StringWriter str = new StringWriter();
|
||||
JcaPEMWriter pemWriter = new JcaPEMWriter(str);
|
||||
pemWriter.writeObject(pemCSR);
|
||||
pemWriter.close();
|
||||
str.close();
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
// public PrivateKey ecdsaKeyFromPrivate(byte[] key) throws CryptoException {
|
||||
// try {
|
||||
// EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(key);
|
||||
// KeyFactory generator = KeyFactory.getInstance("ECDSA", SECURITY_PROVIDER_NAME);
|
||||
// PrivateKey privateKey = generator.generatePrivate(privateKeySpec);
|
||||
//
|
||||
// return privateKey;
|
||||
// } catch (Exception exp) {
|
||||
// throw new CryptoException("Unable to convert byte[] into PrivateKey", exp);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public byte[] hash(byte[] input) {
|
||||
Digest digest = getHashDigest();
|
||||
byte[] retValue = new byte[digest.getDigestSize()];
|
||||
digest.update(input, 0, input.length);
|
||||
digest.doFinal(retValue, 0);
|
||||
return retValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CryptoSuiteFactory getCryptoSuiteFactory() {
|
||||
return HLSDKJCryptoSuiteFactory.instance(); //Factory for this crypto suite.
|
||||
}
|
||||
|
||||
private final AtomicBoolean inited = new AtomicBoolean(false);
|
||||
|
||||
// @Override
|
||||
public void init() throws CryptoException, InvalidArgumentException {
|
||||
if (inited.getAndSet(true)) {
|
||||
throw new InvalidArgumentException("Crypto suite already initialized");
|
||||
} else {
|
||||
resetConfiguration();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Digest getHashDigest() {
|
||||
if ("SHA3".equals(hashAlgorithm)) {
|
||||
return new SHA3Digest();
|
||||
} else {
|
||||
// Default to SHA2
|
||||
return new SHA256Digest();
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Shake256 hash the supplied byte data.
|
||||
// *
|
||||
// * @param in byte array to be hashed.
|
||||
// * @param bitLength of the result.
|
||||
// * @return the hashed byte data.
|
||||
// */
|
||||
// public byte[] shake256(byte[] in, int bitLength) {
|
||||
//
|
||||
// if (bitLength % 8 != 0) {
|
||||
// throw new IllegalArgumentException("bit length not modulo 8");
|
||||
//
|
||||
// }
|
||||
//
|
||||
// final int byteLen = bitLength / 8;
|
||||
//
|
||||
// SHAKEDigest sd = new SHAKEDigest(256);
|
||||
//
|
||||
// sd.update(in, 0, in.length);
|
||||
//
|
||||
// byte[] out = new byte[byteLen];
|
||||
//
|
||||
// sd.doFinal(out, 0, byteLen);
|
||||
//
|
||||
// return out;
|
||||
//
|
||||
// }
|
||||
|
||||
/**
|
||||
* Resets curve name, hash algorithm and cert factory. Call this method when a config value changes
|
||||
*
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private void resetConfiguration() throws CryptoException, InvalidArgumentException {
|
||||
|
||||
setSecurityLevel(securityLevel);
|
||||
|
||||
setHashAlgorithm(hashAlgorithm);
|
||||
|
||||
try {
|
||||
cf = CertificateFactory.getInstance(CERTIFICATE_FORMAT);
|
||||
} catch (CertificateException e) {
|
||||
CryptoException ex = new CryptoException("Cannot initialize " + CERTIFICATE_FORMAT + " certificate factory. Error = " + e.getMessage(), e);
|
||||
logger.error(ex.getMessage(), ex);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
// /* (non-Javadoc)
|
||||
// * @see org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security.CryptoSuite#setProperties(java.util.Properties)
|
||||
// */
|
||||
// @Override
|
||||
void setProperties(Properties properties) throws CryptoException, InvalidArgumentException {
|
||||
if (properties == null) {
|
||||
throw new InvalidArgumentException("properties must not be null");
|
||||
}
|
||||
// if (properties != null) {
|
||||
hashAlgorithm = Optional.ofNullable(properties.getProperty(Config.HASH_ALGORITHM)).orElse(hashAlgorithm);
|
||||
String secLevel = Optional.ofNullable(properties.getProperty(Config.SECURITY_LEVEL)).orElse(Integer.toString(securityLevel));
|
||||
securityLevel = Integer.parseInt(secLevel);
|
||||
if (properties.containsKey(Config.SECURITY_CURVE_MAPPING)) {
|
||||
securityCurveMapping = Config.parseSecurityCurveMappings(properties.getProperty(Config.SECURITY_CURVE_MAPPING));
|
||||
} else {
|
||||
securityCurveMapping = config.getSecurityCurveMapping();
|
||||
}
|
||||
|
||||
final String providerName = properties.containsKey(Config.SECURITY_PROVIDER_CLASS_NAME) ?
|
||||
properties.getProperty(Config.SECURITY_PROVIDER_CLASS_NAME) :
|
||||
config.getSecurityProviderClassName();
|
||||
|
||||
try {
|
||||
SECURITY_PROVIDER = setUpExplicitProvider(providerName);
|
||||
} catch (Exception e) {
|
||||
throw new InvalidArgumentException(format("Getting provider for class name: %s", providerName), e);
|
||||
|
||||
}
|
||||
CERTIFICATE_FORMAT = Optional.ofNullable(properties.getProperty(Config.CERTIFICATE_FORMAT)).orElse(CERTIFICATE_FORMAT);
|
||||
DEFAULT_SIGNATURE_ALGORITHM = Optional.ofNullable(properties.getProperty(Config.SIGNATURE_ALGORITHM)).orElse(DEFAULT_SIGNATURE_ALGORITHM);
|
||||
|
||||
resetConfiguration();
|
||||
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security.CryptoSuite#getProperties()
|
||||
*/
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(Config.HASH_ALGORITHM, hashAlgorithm);
|
||||
properties.setProperty(Config.SECURITY_LEVEL, Integer.toString(securityLevel));
|
||||
properties.setProperty(Config.CERTIFICATE_FORMAT, CERTIFICATE_FORMAT);
|
||||
properties.setProperty(Config.SIGNATURE_ALGORITHM, DEFAULT_SIGNATURE_ALGORITHM);
|
||||
return properties;
|
||||
}
|
||||
|
||||
public byte[] certificateToDER(String certificatePEM) {
|
||||
|
||||
byte[] content = null;
|
||||
|
||||
try (PemReader pemReader = new PemReader(new StringReader(certificatePEM))) {
|
||||
final PemObject pemObject = pemReader.readPemObject();
|
||||
content = pemObject.getContent();
|
||||
|
||||
} catch (IOException e) {
|
||||
// best attempt
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016,2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.security;
|
||||
|
||||
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.InvalidArgumentException;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Collection;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* All packages for PKI key creation/signing/verification implement this interface
|
||||
*/
|
||||
public interface CryptoSuite {
|
||||
|
||||
/**
|
||||
* Get Crypto Suite Factory for this implementation.
|
||||
*
|
||||
* @return MUST return the one and only one instance of a factory that produced this crypto suite.
|
||||
*/
|
||||
|
||||
CryptoSuiteFactory getCryptoSuiteFactory();
|
||||
|
||||
/**
|
||||
* @return the {@link Properties} object containing implementation specific key generation properties
|
||||
*/
|
||||
Properties getProperties();
|
||||
|
||||
/**
|
||||
* Set the Certificate Authority certificates to be used when validating a certificate chain of trust
|
||||
*
|
||||
* @param certificates A collection of {@link Certificate}s
|
||||
* @throws CryptoException
|
||||
*/
|
||||
void loadCACertificates(Collection<Certificate> certificates) throws CryptoException;
|
||||
|
||||
/**
|
||||
* Set the Certificate Authority certificates to be used when validating a certificate chain of trust.
|
||||
*
|
||||
* @param certificates a collection of certificates in PEM format
|
||||
* @throws CryptoException
|
||||
*/
|
||||
void loadCACertificatesAsBytes(Collection<byte[]> certificates) throws CryptoException;
|
||||
|
||||
/**
|
||||
* Generate a key.
|
||||
*
|
||||
* @return the generated key.
|
||||
* @throws CryptoException
|
||||
*/
|
||||
KeyPair keyGen() throws CryptoException;
|
||||
|
||||
/**
|
||||
* Sign the specified byte string.
|
||||
*
|
||||
* @param key the {@link PrivateKey} to be used for signing
|
||||
* @param plainText the byte string to sign
|
||||
* @return the signed data.
|
||||
* @throws CryptoException
|
||||
*/
|
||||
byte[] sign(PrivateKey key, byte[] plainText) throws CryptoException;
|
||||
|
||||
/**
|
||||
* Verify the specified signature
|
||||
*
|
||||
* @param certificate the certificate of the signer as the contents of the PEM file
|
||||
* @param signatureAlgorithm the algorithm used to create the signature.
|
||||
* @param signature the signature to verify
|
||||
* @param plainText the original text that is to be verified
|
||||
* @return {@code true} if the signature is successfully verified; otherwise {@code false}.
|
||||
* @throws CryptoException
|
||||
*/
|
||||
boolean verify(byte[] certificate, String signatureAlgorithm, byte[] signature, byte[] plainText) throws CryptoException;
|
||||
|
||||
/**
|
||||
* Hash the specified text byte data.
|
||||
*
|
||||
* @param plainText the text to hash
|
||||
* @return the hashed data.
|
||||
*/
|
||||
byte[] hash(byte[] plainText);
|
||||
|
||||
/**
|
||||
* Generates a CertificationRequest
|
||||
*
|
||||
* @param user
|
||||
* @param keypair
|
||||
* @return String in PEM format for certificate request.
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
String generateCertificationRequest(String user, KeyPair keypair) throws InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Convert bytes in PEM format to Certificate.
|
||||
*
|
||||
* @param certBytes
|
||||
* @return Certificate
|
||||
* @throws CryptoException
|
||||
*/
|
||||
Certificate bytesToCertificate(byte[] certBytes) throws CryptoException, CryptoException;
|
||||
|
||||
/**
|
||||
* The CryptoSuite factory. Currently {@link #getCryptoSuite} will always
|
||||
* give you a {@link CryptoPrimitives} object
|
||||
*/
|
||||
|
||||
class Factory {
|
||||
private Factory() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a crypto suite with the default factory with default settings.
|
||||
* Settings which can define such parameters such as curve strength, are specific to the crypto factory.
|
||||
*
|
||||
* @return Default crypto suite.
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
* @throws ClassNotFoundException
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws NoSuchMethodException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
|
||||
public static CryptoSuite getCryptoSuite() throws IllegalAccessException, InstantiationException,
|
||||
ClassNotFoundException, CryptoException, InvalidArgumentException, NoSuchMethodException,
|
||||
InvocationTargetException {
|
||||
return CryptoSuiteFactory.getDefault().getCryptoSuite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a crypto suite with the default factory with settings defined by properties
|
||||
* Properties are uniquely defined by the specific crypto factory.
|
||||
*
|
||||
* @param properties properties that define suite characteristics such as strength, curve, hashing .
|
||||
* @return
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
* @throws ClassNotFoundException
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
* @throws NoSuchMethodException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
public static CryptoSuite getCryptoSuite(Properties properties) throws IllegalAccessException, InstantiationException,
|
||||
ClassNotFoundException, CryptoException, InvalidArgumentException, NoSuchMethodException,
|
||||
InvocationTargetException {
|
||||
return CryptoSuiteFactory.getDefault().getCryptoSuite(properties);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2016,2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.security;
|
||||
|
||||
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.InvalidArgumentException;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Factory to produce a set of crypto suite implementations offering differing cryptographic algorithms and strengths.
|
||||
*/
|
||||
|
||||
public interface CryptoSuiteFactory {
|
||||
|
||||
/**
|
||||
* If set as the default security provider then default crypto suite will not use explicit
|
||||
* provider
|
||||
*/
|
||||
|
||||
String DEFAULT_JDK_PROVIDER = "org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.security.default_jdk_provider";
|
||||
|
||||
/**
|
||||
* Produce a crypto suite by specified by these properties.
|
||||
* Properties are unique to each Crypto Suite implementation.
|
||||
*
|
||||
* @param properties
|
||||
* @return
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
|
||||
CryptoSuite getCryptoSuite(Properties properties) throws CryptoException, InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Return a default crypto suite
|
||||
*
|
||||
* @return
|
||||
* @throws CryptoException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
|
||||
CryptoSuite getCryptoSuite() throws CryptoException, InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* This will return the default Crypto Suite Factory implementation.
|
||||
* Can be overwritten by org.hyperledger.fabric.com.chinaunicom.ebtp.mall.cloud.attachment.sdk.crypto.default_crypto_suite_factory property.
|
||||
* see
|
||||
* Classes specified by this property must implement a public static method <b>instance</b> that
|
||||
* returns back a single instance of this factory.
|
||||
*
|
||||
* @return A single instance of a CryptoSuiteFactory.
|
||||
* @throws ClassNotFoundException
|
||||
* @throws IllegalAccessException
|
||||
* @throws InstantiationException
|
||||
* @throws NoSuchMethodException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
|
||||
static CryptoSuiteFactory getDefault() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
|
||||
|
||||
return HLSDKJCryptoSuiteFactory.getDefault();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016,2017 DTCC, Fujitsu Australia Software Technology, IBM - All Rights Reserved.
|
||||
*
|
||||
* 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 com.chinaunicom.mall.ebtp.common.crypto.security;
|
||||
|
||||
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.InvalidArgumentException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.helper.Config;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* SDK's Default implementation of CryptoSuiteFactory.
|
||||
*/
|
||||
public class HLSDKJCryptoSuiteFactory implements CryptoSuiteFactory {
|
||||
private static final Config config = Config.getConfig();
|
||||
private static final int SECURITY_LEVEL = config.getSecurityLevel();
|
||||
private static final String HASH_ALGORITHM = config.getHashAlgorithm();
|
||||
|
||||
private HLSDKJCryptoSuiteFactory() {
|
||||
|
||||
}
|
||||
|
||||
private static final Map<Properties, CryptoSuite> cache = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public CryptoSuite getCryptoSuite(Properties properties) throws CryptoException, InvalidArgumentException {
|
||||
|
||||
CryptoSuite ret = cache.get(properties);
|
||||
if (ret == null) {
|
||||
try {
|
||||
CryptoPrimitives cp = new CryptoPrimitives();
|
||||
cp.setProperties(properties);
|
||||
cp.init();
|
||||
ret = cp;
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
cache.put(properties, ret);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CryptoSuite getCryptoSuite() throws CryptoException, InvalidArgumentException {
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.put(Config.SECURITY_LEVEL, SECURITY_LEVEL);
|
||||
properties.put(Config.HASH_ALGORITHM, HASH_ALGORITHM);
|
||||
|
||||
return getCryptoSuite(properties);
|
||||
}
|
||||
|
||||
private static final HLSDKJCryptoSuiteFactory INSTANCE = new HLSDKJCryptoSuiteFactory();
|
||||
|
||||
static synchronized HLSDKJCryptoSuiteFactory instance() {
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private static CryptoSuiteFactory theFACTORY = null; // one and only factory.
|
||||
|
||||
static final synchronized CryptoSuiteFactory getDefault() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
|
||||
|
||||
if (null == theFACTORY) {
|
||||
|
||||
String cf = config.getDefaultCryptoSuiteFactory();
|
||||
if (null == cf || cf.isEmpty() || cf.equals(HLSDKJCryptoSuiteFactory.class.getName())) { // Use this class as the factory.
|
||||
|
||||
theFACTORY = HLSDKJCryptoSuiteFactory.instance();
|
||||
|
||||
} else {
|
||||
|
||||
// Invoke static method instance on factory class specified by config properties.
|
||||
// In this case this class will no longer be used as the factory.
|
||||
|
||||
Class<?> aClass = Class.forName(cf);
|
||||
|
||||
Method method = aClass.getMethod("instance");
|
||||
Object theFACTORYObject = method.invoke(null);
|
||||
if (null == theFACTORYObject) {
|
||||
throw new InstantiationException(String.format("Class specified by %s has instance method returning null. Expected object implementing CryptoSuiteFactory interface.", cf));
|
||||
}
|
||||
|
||||
if (!(theFACTORYObject instanceof CryptoSuiteFactory)) {
|
||||
|
||||
throw new InstantiationException(String.format("Class specified by %s has instance method returning a class %s which does not implement interface CryptoSuiteFactory ",
|
||||
cf, theFACTORYObject.getClass().getName()));
|
||||
|
||||
}
|
||||
|
||||
theFACTORY = (CryptoSuiteFactory) theFACTORYObject;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return theFACTORY;
|
||||
}
|
||||
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
package com.chinaunicom.mall.ebtp.common.crypto.service;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.InvalidArgumentException;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.security.CryptoPrimitives;
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.tenderfee.test;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.bouncycastle.crypto.CryptoException;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.security.PrivateKey;
|
||||
|
||||
@Slf4j
|
||||
public class CrypServiceImpl {
|
||||
|
||||
private static final String SIGNING_ALGORITHM = "SHA256withECDSA";
|
||||
private static final String DATA_PATH = "C:\\Users\\user\\Downloads\\debian-edu-10.8.0-amd64-netinst.iso.torrent";
|
||||
|
||||
// 私钥文件路径 - 加密
|
||||
private static String PEM_PATH = "admin_certPrivate.pem";
|
||||
|
||||
// 证书文件路径 - 解密
|
||||
private static String CRT_PATH = "admin.crt";
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, CryptoException, InvalidArgumentException, UnsupportedEncodingException {
|
||||
|
||||
URL pem = test.class.getClassLoader().getResource(PEM_PATH);
|
||||
URL crt = test.class.getClassLoader().getResource(CRT_PATH);
|
||||
|
||||
PEM_PATH = pem.getPath();
|
||||
CRT_PATH = crt.getPath();
|
||||
|
||||
// example of HashMap entity, treeMap can also work out,
|
||||
// but LinkedHashMap is NOT supported
|
||||
// Map<String,String> map = new HashMap<>(1);
|
||||
// map.put("SECTION_ID","L3307");
|
||||
// map.put("DOCUMENT_ID","8533");
|
||||
// map.put("CONTENT_FILE_HASH","12321123");
|
||||
// map.put("TP_ID","L3307A");
|
||||
//
|
||||
// String signature = signObject(map,PEM_PATH);
|
||||
// System.out.println("signature of Map: "+signature);
|
||||
// boolean isOk = verifyObject(signature,map,CRT_PATH);
|
||||
// System.out.println("verify result of Map: "+ isOk);
|
||||
|
||||
// example of bean entity
|
||||
|
||||
String pemVal = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjF+tq8oc1tNjot69\n" +
|
||||
"9OQgzr7Dqg1OkVo4PY4tKBL8+82hRANCAARKLIuOloTZe1B0J0k+CITZdsx8Gham\n" +
|
||||
"JTuxCRGLdCLpq6wHHGEqWn9VDkwk5eX6OYQxYuBRiPZp7gP/njpx5CkF\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
|
||||
String crtVal = "-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICgzCCAimgAwIBAgIULDLuWrkCL3UaWO5u7yiu8UghEjEwCgYIKoZIzj0EAwIw\n" +
|
||||
"ZzELMAkGA1UEBhMCQ04xETAPBgNVBAgTCFNoYW5Eb25nMQ4wDAYDVQQHEwVKaU5h\n" +
|
||||
"bjEYMBYGA1UEChMPYWRtaW50MDgxMmFvcmczMRswGQYDVQQDExJjYS5hZG1pbnQw\n" +
|
||||
"ODEyYW9yZzMwHhcNMjEwODE3MDExODAwWhcNMjIwODE3MDEyMzAwWjAzMRwwDQYD\n" +
|
||||
"VQQLEwZjbGllbnQwCwYDVQQLEwRvcmczMRMwEQYDVQQDDAphZG1pbkBvcmczMFkw\n" +
|
||||
"EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESiyLjpaE2XtQdCdJPgiE2XbMfBoWpiU7\n" +
|
||||
"sQkRi3Qi6ausBxxhKlp/VQ5MJOXl+jmEMWLgUYj2ae4D/546ceQpBaOB5jCB4zAO\n" +
|
||||
"BgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUcyAwVSk9V615\n" +
|
||||
"ryVrpykYwJbUs7UwKwYDVR0jBCQwIoAgOIS8Yvvj2hRg0V3+x659Mn60B09bt8Fl\n" +
|
||||
"eRcf79zjGRkwFAYDVR0RBA0wC4IJSlpaSEpTLTcyMGEGCCoDBAUGBwgBBFV7ImF0\n" +
|
||||
"dHJzIjp7ImhmLkFmZmlsaWF0aW9uIjoib3JnMyIsImhmLkVucm9sbG1lbnRJRCI6\n" +
|
||||
"ImFkbWluQG9yZzMiLCJoZi5UeXBlIjoiY2xpZW50In19MAoGCCqGSM49BAMCA0gA\n" +
|
||||
"MEUCIQCi/6V6gmt4k5MUSfym9RFGqPwmD1hyWmtWKj448PXALAIgQfHHiX+P2M6k\n" +
|
||||
"GqneZYuHHxazU37s5ZaFBPylOJJEO2Y=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
// 需正确设置bean的@JSONField,以确保解析到的字段名称与文档一致
|
||||
// List<BidTenderFeeBaseParam> paramList = new ArrayList<>();
|
||||
// BidTenderFeeBaseParam bean = new BidTenderFeeBaseParam();
|
||||
// bean.setTenderId("8533");
|
||||
// bean.setShoppingCartId("L3307");
|
||||
// bean.setAmount("1000");
|
||||
// bean.setTpId("L3307A");
|
||||
// bean.setSectionId("1111");
|
||||
|
||||
// paramList.add(bean);
|
||||
// // 用于签名的Bean将被signObject转换为json(String,然后转换为byte[]),请确保该json只包含文档规定的业务字段,且“SGIN"不应包含其中
|
||||
// String signatureOfBean = signObject2(paramList,pemVal);
|
||||
// // 生成的签名现在可以追加到签名字段
|
||||
// System.out.println("signature of Bean: "+signatureOfBean);
|
||||
// boolean isOkBean = verifyValue(signatureOfBean,paramList,crtVal);
|
||||
// System.out.println("verify result of Bean: "+ isOkBean);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据实体
|
||||
*
|
||||
* @param signatureString Base64加密的密钥
|
||||
* @param entity 数据实体
|
||||
* @param crtKey 证书路径
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyValue(String signatureString, Object entity, String crtKey) {
|
||||
return verifyValue(signatureString, JSON.toJSONBytes(entity, SerializerFeature.MapSortField, SerializerFeature.SortField), crtKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证二进制数据串
|
||||
*
|
||||
* @param signatureString Base64加密的密钥
|
||||
* @param plainData 源数据
|
||||
* @param crtKey 证书路径
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyValue(String signatureString, byte[] plainData, String crtKey) {
|
||||
byte[] signature = Base64.decode(signatureString);
|
||||
CryptoPrimitives cp = null;
|
||||
boolean result = false;
|
||||
try {
|
||||
cp = new CryptoPrimitives();
|
||||
cp.init();
|
||||
byte[] crtBytes = crtKey.getBytes();
|
||||
result = cp.verify(crtBytes, SIGNING_ALGORITHM, signature, plainData);
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | InvalidArgumentException | com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证二进制数据串
|
||||
*
|
||||
* @param signatureString Base64加密的密钥
|
||||
* @param plainData 源数据
|
||||
* @param crtPath 证书路径
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyBytes(String signatureString, byte[] plainData, String crtPath) {
|
||||
byte[] signature = Base64.decode(signatureString);
|
||||
CryptoPrimitives cp = null;
|
||||
boolean result = false;
|
||||
try {
|
||||
cp = new CryptoPrimitives();
|
||||
cp.init();
|
||||
byte[] crtBytes = readAsBytes(crtPath);
|
||||
result = cp.verify(crtBytes, SIGNING_ALGORITHM, signature, plainData);
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | InvalidArgumentException | com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据实体
|
||||
*
|
||||
* @param signatureString Base64加密的密钥
|
||||
* @param entity 数据实体
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyObject(String signatureString, Object entity) {
|
||||
URL crt = test.class.getClassLoader().getResource(CRT_PATH);
|
||||
return verifyObject(signatureString, entity, crt.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证数据实体
|
||||
*
|
||||
* @param signatureString Base64加密的密钥
|
||||
* @param entity 数据实体
|
||||
* @param crtPath 证书路径
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyObject(String signatureString, Object entity, String crtPath) {
|
||||
return verifyBytes(signatureString, JSON.toJSONBytes(entity, SerializerFeature.MapSortField, SerializerFeature.SortField), crtPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
*
|
||||
* @param object 数据实体
|
||||
* @return Base64加密的密钥
|
||||
*/
|
||||
public static String signObject(Object object) {
|
||||
URL pem = test.class.getClassLoader().getResource(PEM_PATH);
|
||||
return signObject(object, pem.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
*
|
||||
* @param object 数据实体
|
||||
* @param privateVal 密钥路径
|
||||
* @return Base64加密的密钥
|
||||
*/
|
||||
public static String signObject2(Object object, String privateVal) {
|
||||
CryptoPrimitives cp = null;
|
||||
byte[] signature = null;
|
||||
try {
|
||||
cp = new CryptoPrimitives();
|
||||
cp.init();
|
||||
byte[] pemBytes = privateVal.getBytes();
|
||||
PrivateKey key = cp.bytesToPrivateKey(pemBytes);
|
||||
signature = cp.sign(key, JSON.toJSONBytes(object, SerializerFeature.MapSortField, SerializerFeature.SortField));
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | InvalidArgumentException | com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return signature == null ? "" : Base64.toBase64String(signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
*
|
||||
* @param object 数据实体
|
||||
* @param privatePath 密钥路径
|
||||
* @return Base64加密的密钥
|
||||
*/
|
||||
public static String signObject(Object object, String privatePath) {
|
||||
CryptoPrimitives cp = null;
|
||||
byte[] signature = null;
|
||||
try {
|
||||
cp = new CryptoPrimitives();
|
||||
cp.init();
|
||||
byte[] pemBytes = readAsBytes(privatePath);
|
||||
PrivateKey key = cp.bytesToPrivateKey(pemBytes);
|
||||
signature = cp.sign(key, JSON.toJSONBytes(object, SerializerFeature.MapSortField, SerializerFeature.SortField));
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException | InvalidArgumentException | com.chinaunicom.mall.ebtp.common.crypto.exception.CryptoException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return signature == null ? "" : Base64.toBase64String(signature);
|
||||
}
|
||||
|
||||
private static byte[] readAsBytes(String path) {
|
||||
File file = new File(path);
|
||||
byte[] result = {};
|
||||
try (FileInputStream is = new FileInputStream(file);
|
||||
BufferedInputStream bis = new BufferedInputStream(is);) {
|
||||
result = IOUtils.toByteArray(bis);
|
||||
} catch (FileNotFoundException e) {
|
||||
log.error(path + " not found");
|
||||
} catch (IOException e) {
|
||||
log.error(e.toString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
package com.chinaunicom.mall.ebtp.common.crypto.tenderfee;
|
||||
|
||||
|
||||
import com.chinaunicom.mall.ebtp.common.crypto.exception.InvalidArgumentException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.crypto.CryptoException;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
|
||||
@Slf4j
|
||||
public class test {
|
||||
|
||||
// 私钥文件路径 - 加密
|
||||
private static String PEM_PATH = "admin_certPrivate.pem";
|
||||
|
||||
// 证书文件路径 - 解密
|
||||
private static String CRT_PATH = "admin.crt";
|
||||
|
||||
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, CryptoException, InvalidArgumentException, UnsupportedEncodingException {
|
||||
|
||||
//String token = AccessToken.tokenCreate();
|
||||
|
||||
URL pem = test.class.getClassLoader().getResource(PEM_PATH);
|
||||
URL crt = test.class.getClassLoader().getResource(CRT_PATH);
|
||||
|
||||
PEM_PATH = pem.getPath();
|
||||
CRT_PATH = crt.getPath();
|
||||
|
||||
|
||||
// example of bean entity
|
||||
String pemVal = "-----BEGIN PRIVATE KEY-----\n" +
|
||||
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgjF+tq8oc1tNjot69\n" +
|
||||
"9OQgzr7Dqg1OkVo4PY4tKBL8+82hRANCAARKLIuOloTZe1B0J0k+CITZdsx8Gham\n" +
|
||||
"JTuxCRGLdCLpq6wHHGEqWn9VDkwk5eX6OYQxYuBRiPZp7gP/njpx5CkF\n" +
|
||||
"-----END PRIVATE KEY-----";
|
||||
|
||||
// 需正确设置bean的@JSONField,以确保解析到的字段名称与文档一致
|
||||
// List<BidTenderFeeBaseParam> paramList = new ArrayList<>();
|
||||
// BidTenderFeeBaseParam bean = new BidTenderFeeBaseParam();
|
||||
// bean.setTenderId("8533");
|
||||
// bean.setShoppingCartId("L3307");
|
||||
// bean.setAmount("1000");
|
||||
// bean.setTpId("L3307A");
|
||||
// bean.setSectionId("1111");
|
||||
//
|
||||
// paramList.add(bean);
|
||||
// // 用于签名的Bean将被signObject转换为json(String,然后转换为byte[]),请确保该json只包含文档规定的业务字段,且“SGIN"不应包含其中
|
||||
// String signatureOfBean = CrypServiceImpl.signObject2(paramList,pemVal);//CrypService.signObject(paramList);
|
||||
// System.out.println("signature of Bean: "+signatureOfBean);
|
||||
// boolean isOkBean = CrypServiceImpl.verifyObject(signatureOfBean,paramList);
|
||||
// System.out.println("verify result of Bean: "+ isOkBean);
|
||||
// String signatureOfBean = signObject(paramList,PEM_PATH);
|
||||
// // 生成的签名现在可以追加到签名字段
|
||||
// System.out.println("signature of Bean: "+signatureOfBean);
|
||||
// boolean isOkBean = verifyObject(signatureOfBean,paramList,CRT_PATH);
|
||||
// System.out.println("verify result of Bean: "+ isOkBean);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user