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

cn.teleinfo.idpointer.sdk.core.HandleSignature Maven / Gradle / Ivy

Go to download

基于Java语言开发的工业互联网标识解析体系客户端软件开发工具包,应用通过集成 id-pointer-sdk,快速对接标识解析、标识注册、标识维护等功能服务。

The newest version!
/**********************************************************************\
 © COPYRIGHT 2019 Corporation for National Research Initiatives (CNRI);
                        All rights reserved.

        The HANDLE.NET software is made available subject to the
      Handle.Net Public License Agreement, which may be obtained at
          http://hdl.handle.net/20.1000/112 or hdl:20.1000/112
\**********************************************************************/

package cn.teleinfo.idpointer.sdk.core;

import cn.teleinfo.idpointer.sdk.core.stream.xml.XParser;
import cn.teleinfo.idpointer.sdk.core.stream.xml.XTag;
import cn.teleinfo.idpointer.sdk.core.trust.JsonWebSignature;

import java.io.StringReader;
import java.security.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * A signature over some handle values.  The form of the signature is two handle values, one with type 10320/sig.digest containing a digest of all the signed values,
 * and a second of type 10320/sig.sig containing a signature of the digest value.  Example data:
 * 
{@code
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * }
* and *
{@code
 * 
 * 302C02142306D496402DC1CE701244AD0905A38122CFA9FD0214432390E2C7132EFDC2F516FB6B9C670538B8CA32
 * 
 * }
* * The hash of a handle value is a hash of its binary representation starting at offset 8, which corresponds to excluding the index and the timestamp from the hash. * The signature is a signature of the binary represenation of the digest value, again excluding offset and timestamp. * The signature value specifies the index of the corresponding digest value. The signed handle is specifed in the digest value. * The signature value specifies the signer as handle and index. It can actually contain multiple signatures of multiple signers. * The signature algorithm defaults to SHA1with(key-algorithm) if not specified. * * @deprecated Use {@link JsonWebSignature} and allied classes. */ @Deprecated public class HandleSignature { public static final byte[] METADATA_TYPE = Util.encodeString("10320/sig.digest"); public static final byte[] SIGNATURE_TYPE = Util.encodeString("10320/sig.sig"); public static class Digest { final String algorithm; final byte[] digest; public Digest(String algorithm, byte[] digest) { this.algorithm = algorithm; this.digest = digest; } public String getAlgorithm() { return algorithm; } public byte[] getDigest() { return digest; } } public static class DigestsValue { final String handle; @SuppressWarnings("hiding") final Map> digests; public DigestsValue(String handle, Map> digests) { this.handle = handle; this.digests = digests; } public String getHandle() { return handle; } public Map> getDigests() { return digests; } public static DigestsValue ofXml(String xml) throws Exception { XParser parser = new XParser(); XTag root = parser.parse(new StringReader(xml), false); String handle = root.getAttribute("hdl"); Map> digests = new HashMap<>(); if (root.getSubTags() != null) { for (XTag child : root.getSubTags()) { int index; try { index = Integer.parseInt(child.getAttribute("index")); } catch (Exception e) { throw new Exception("bad index attribute " + child, e); } List digestList = new ArrayList<>(); for (Map.Entry entry : child.getAttributes().entrySet()) { String name = entry.getKey(); if ("index".equals(name)) continue; digestList.add(new Digest(name, Util.encodeHexString(entry.getValue()))); } if (digests.containsKey(Integer.valueOf(index))) throw new Exception("duplicate index attribute " + child); digests.put(Integer.valueOf(index), digestList); } } return new DigestsValue(handle, digests); } } final HandleValue digestsValue; final DigestsValue parsedDigestsValue; final String algorithm; final ValueReference signer; final byte[] signature; public HandleSignature(HandleValue digestsValue, DigestsValue parsedDigestValue, String algorithm, ValueReference signer, byte[] signature) throws Exception { this.digestsValue = digestsValue; this.parsedDigestsValue = parsedDigestValue; this.algorithm = algorithm; this.signer = signer; this.signature = signature; } public String getHandle() { return parsedDigestsValue.getHandle(); } public HandleValue getDigestsValue() { return digestsValue; } public DigestsValue getParsedDigestsValue() { return parsedDigestsValue; } public String getAlgorithm() { return algorithm; } public ValueReference getSigner() { return signer; } public byte[] getSignature() { return signature; } @Override public String toString() { return "HandleSignature [digestsValue=" + digestsValue + ", algorithm=" + algorithm + ", signer=" + signer + "]"; } public static final int VALUE_DIGEST_OFFSET = Encoder.INT_SIZE * 2; public static void updateForHandleValue(MessageDigest digest, byte[] encodedHandleValue) { digest.update(encodedHandleValue, VALUE_DIGEST_OFFSET, encodedHandleValue.length - VALUE_DIGEST_OFFSET); } public static void updateForHandleValue(Signature sig, byte[] encodedHandleValue) throws SignatureException { sig.update(encodedHandleValue, VALUE_DIGEST_OFFSET, encodedHandleValue.length - VALUE_DIGEST_OFFSET); } public boolean verifySignature(PublicKey pubKey) throws Exception { String alg = algorithm; if (alg == null) alg = Util.getSigIdFromHashAlgId(Common.HASH_ALG_SHA1, pubKey.getAlgorithm()); Signature sig = Signature.getInstance(alg); sig.initVerify(pubKey); updateForHandleValue(sig, Encoder.encodeHandleValue(digestsValue)); return sig.verify(signature); } public boolean verifyValue(String handle, HandleValue value) throws NoSuchAlgorithmException { if (!Util.equalsPrefixCI(handle, getHandle())) return false; @SuppressWarnings("hiding") List digests = parsedDigestsValue.getDigests().get(Integer.valueOf(value.getIndex())); if (digests == null) return false; byte[] encodedHandleValue = Encoder.encodeHandleValue(value); boolean foundSha = false; for (Digest digest : digests) { MessageDigest messageDigest = getMessageDigest(digest.getAlgorithm()); byte[] checkDigest; synchronized (messageDigest) { messageDigest.reset(); updateForHandleValue(messageDigest, encodedHandleValue); checkDigest = messageDigest.digest(); } if (!Util.equals(checkDigest, digest.getDigest())) return false; if (digest.getAlgorithm().toLowerCase().startsWith("sha")) foundSha = true; } return foundSha; } public boolean signsMissingValues(HandleValue[] values) { List signedIndices = new ArrayList<>(parsedDigestsValue.getDigests().keySet()); for (HandleValue value : values) { signedIndices.remove(Integer.valueOf(value.getIndex())); } return !signedIndices.isEmpty(); } private static ConcurrentMap digests = new ConcurrentHashMap<>(); private static MessageDigest getMessageDigest(String algorithm) throws NoSuchAlgorithmException { MessageDigest res = digests.get(algorithm); if (res != null) return res; MessageDigest newDigest = MessageDigest.getInstance(algorithm); digests.putIfAbsent(algorithm, newDigest); return newDigest; } public static List getSignatures(HandleValue[] values, HandleValue value, boolean throwOnError) throws Exception { try { if (!value.hasType(SIGNATURE_TYPE)) return null; XParser parser = new XParser(); XTag root = parser.parse(new StringReader(value.getDataAsString()), false); String defaultSigner = root.getAttribute("signer"); String defaultSignerIndex = root.getAttribute("signerIndex", "300"); String ofIndex = root.getAttribute("ofIndex", root.getAttribute("ofindex")); String handle = root.getAttribute("hdl"); HandleValue digestsValue = getValueOfIndex(values, ofIndex); if (digestsValue == null) throw new Exception("Unable to find digests value for signature value " + root); DigestsValue parsedDigestValue = DigestsValue.ofXml(digestsValue.getDataAsString()); if (handle != null && !Util.equalsPrefixCI(handle, parsedDigestValue.getHandle())) { throw new Exception("Handle does not match in signature and digests value " + root); } List res = new ArrayList<>(); for (XTag child : root.getSubTags()) { try { res.add(getHandleSignature(child, digestsValue, parsedDigestValue, defaultSigner, defaultSignerIndex)); } catch (Exception e) { if (throwOnError) throw e; } } return res; } catch (Exception e) { if (throwOnError) throw e; else return null; } } public static List getSignaturesQuietly(HandleValue[] values) { try { return getSignatures(values, false); } catch (Exception e) { throw new AssertionError(e); } } public static List getSignatures(HandleValue[] values, boolean throwOnError) throws Exception { List res = new ArrayList<>(); for (HandleValue value : values) { List sublist = getSignatures(values, value, throwOnError); if (sublist != null) res.addAll(sublist); } return res; } private static HandleValue getValueOfIndex(HandleValue[] values, String ofIndex) { HandleValue digestsValue = null; for (HandleValue candidate : values) { if (String.valueOf(candidate.getIndex()).equals(ofIndex)) { digestsValue = candidate; break; } } return digestsValue; } private static HandleSignature getHandleSignature(XTag child, HandleValue digestsValue, DigestsValue parsedDigestValue, String defaultSigner, String defaultSignerIndex) throws Exception { String algorithm = child.getAttribute("alg"); String signer = child.getAttribute("signer", defaultSigner); String signerIndex = child.getAttribute("signerIndex", defaultSignerIndex); String signatureHex = child.getStrValue(); ValueReference signerRef; try { signerRef = new ValueReference(Util.encodeString(signer), Integer.parseInt(signerIndex)); } catch (NumberFormatException e) { throw new Exception("Invalid signer index " + signerIndex + " in " + child, e); } return new HandleSignature(digestsValue, parsedDigestValue, algorithm, signerRef, Util.encodeHexString(signatureHex)); } public static HandleValue createDigestsValue(int index, String handle, HandleValue[] values) { XTag root = new XTag("digests"); root.setAttribute("hdl", handle); for (HandleValue value : values) { XTag child = new XTag("val"); child.setAttribute("index", value.getIndex()); byte[] encodedHandleValue = Encoder.encodeHandleValue(value); for (String alg : new String[] { "md5", "sha1" }) { MessageDigest messageDigest; try { messageDigest = getMessageDigest(alg); } catch (NoSuchAlgorithmException e) { throw new AssertionError(e); } byte[] digest; synchronized (messageDigest) { messageDigest.reset(); updateForHandleValue(messageDigest, encodedHandleValue); digest = messageDigest.digest(); } child.setAttribute(alg, Util.decodeHexString(digest, false)); } root.addSubTag(child); } return new HandleValue(index, METADATA_TYPE, Util.encodeString(root.toString())); } public static HandleValue createSignatureValue(int index, String handle, ValueReference signer, String alg, PrivateKey privKey, HandleValue digestsValue) throws Exception { XTag root = new XTag("signature"); if (handle != null) root.setAttribute("hdl", handle); root.setAttribute("ofindex", digestsValue.getIndex()); root.setAttribute("signer", Util.decodeString(signer.handle)); root.setAttribute("signerIndex", signer.index); if (alg == null) alg = Util.getDefaultSigId(privKey.getAlgorithm()); XTag child = new XTag("sig"); child.setAttribute("alg", alg); child.setAttribute("signer", Util.decodeString(signer.handle)); child.setAttribute("signerIndex", signer.index); Signature sig = Signature.getInstance(alg); sig.initSign(privKey); updateForHandleValue(sig, Encoder.encodeHandleValue(digestsValue)); byte[] signature = sig.sign(); child.setValue(Util.decodeHexString(signature, false)); root.addSubTag(child); return new HandleValue(index, SIGNATURE_TYPE, Util.encodeString(root.toString())); } public static HandleValue[] signedHandleValues(String handle, HandleValue[] values, HandleSignature signature, PublicKey pubKey, boolean throwOnError) throws Exception { if (!Util.equalsPrefixCI(handle, signature.getHandle())) { return new HandleValue[0]; } try { if (!signature.verifySignature(pubKey)) return new HandleValue[0]; } catch (Exception e) { if (throwOnError) throw e; else return new HandleValue[0]; } List res = new ArrayList<>(); for (HandleValue value : values) { try { if (signature.verifyValue(handle, value)) res.add(value); } catch (Exception e) { if (throwOnError) throw e; } } return res.toArray(new HandleValue[res.size()]); } public static boolean signsAllValues(String handle, HandleValue[] values, HandleSignature signature, PublicKey pubKey, boolean throwOnError) throws Exception { if (!Util.equalsPrefixCI(handle, signature.getHandle())) { return false; } try { if (!signature.verifySignature(pubKey)) return false; } catch (Exception e) { if (throwOnError) throw e; else return false; } for (HandleValue value : values) { try { if (valueNeedsSignature(value) && !signature.verifyValue(handle, value)) return false; } catch (Exception e) { if (throwOnError) throw e; } } return true; } public static boolean valueNeedsSignature(HandleValue value) { if (value.hasType(SIGNATURE_TYPE) || value.hasType(METADATA_TYPE) || !value.publicRead) return false; else return true; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy