From dd45e938564249a5e6897bd92dd29808d8990868 Mon Sep 17 00:00:00 2001 From: rudolf Date: Fri, 24 Oct 2003 08:34:56 +0000 Subject: MOA-ID version 1.1 (initial) git-svn-id: https://joinup.ec.europa.eu/svn/moa-idspss/trunk@19 d688527b-c9ab-4aba-bd8d-4036d912da1d --- .../moa/id/auth/parser/ECDSAKeyValueConverter.java | 350 +++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 id.server/src/at/gv/egovernment/moa/id/auth/parser/ECDSAKeyValueConverter.java (limited to 'id.server/src/at/gv/egovernment/moa/id/auth/parser/ECDSAKeyValueConverter.java') diff --git a/id.server/src/at/gv/egovernment/moa/id/auth/parser/ECDSAKeyValueConverter.java b/id.server/src/at/gv/egovernment/moa/id/auth/parser/ECDSAKeyValueConverter.java new file mode 100644 index 000000000..c28cfac76 --- /dev/null +++ b/id.server/src/at/gv/egovernment/moa/id/auth/parser/ECDSAKeyValueConverter.java @@ -0,0 +1,350 @@ +package at.gv.egovernment.moa.id.auth.parser; + +import iaik.security.ecc.ecdsa.ECDSAParameter; +import iaik.security.ecc.ecdsa.ECPublicKey; +import iaik.security.ecc.math.ecgroup.ECGroupFactory; +import iaik.security.ecc.math.ecgroup.ECPoint; +import iaik.security.ecc.math.ecgroup.EllipticCurve; +import iaik.security.ecc.math.ecgroup.ProjectiveCoordinate; +import iaik.security.ecc.math.field.Field; +import iaik.security.ecc.math.field.FieldElement; +import iaik.security.ecc.math.field.FieldFactory; +import iaik.security.ecc.math.field.Value; +import iaik.security.ecc.parameter.ECCParameterFactory; +import iaik.security.ecc.spec.ECCParameterSpec; +import java.math.BigInteger; +import java.security.PublicKey; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; +import java.net.URL; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import at.gv.egovernment.moa.util.Constants; + +/** + * @author Stefan Knirsch + * @version $Id$ + * + */ +public class ECDSAKeyValueConverter +{ + /** Namespaces */ + public static final String NAMESPACE_XSI = "http://www.w3.org/2001/XMLSchema-instance"; + + /** + * Method element2ECDSAPublicKey. + * @param keyValueElem a DomElement containing an ECDSA Public Key + * @return PublicKey a java.security.publicKey - object + * @throws Exception on any error + */ + + public static PublicKey element2ECDSAPublicKey(Element keyValueElem) throws Exception + { + String ecdsaNS = Constants.ECDSA_NS_URI; + // Domain parameters + Element domainParams = getChildElement(keyValueElem, ecdsaNS, "DomainParameters", 1); + if (domainParams == null) throw new Exception("Domain parameters must not be implicit."); + Element namedCurve = getChildElement(domainParams, ecdsaNS, "NamedCurve", 1); + ECCParameterSpec eccParameterSpec; + if (namedCurve != null) + { + URL curveNameURN = new URL(namedCurve.getAttributeNS(null, "URN")); + ECCParameterFactory eccParamFactory = ECCParameterFactory.getInstance(); + eccParameterSpec = eccParamFactory.getParameterByOID(curveNameURN.getPath().substring(4)); + } + else + { + Element excplicitParams = getChildElement(domainParams, ecdsaNS, "ExplicitParams", 1); + Element fieldParams = getChildElement(excplicitParams, ecdsaNS, "FieldParams", 1); + Element curveParams = getChildElement(excplicitParams, ecdsaNS, "CurveParams", 1); + Element basePointParams = getChildElement(excplicitParams, ecdsaNS, "BasePointParams", 1); + + // Field parameters + String fieldParamsTypeStr = fieldParams.getAttributeNS(NAMESPACE_XSI, "type"); + String ecdsaNSPrefix = getECDSANSPrefix(fieldParams); + BigInteger p = null; + int fieldParamsType = 0; + final int FIELD_TYPE_PRIME = 1; + final int FIELD_TYPE_TNB = 2; + final int FIELD_TYPE_PNB = 3; + int m = -1, k = -1, k1 = -1, k2 = -1, k3 = -1; + if (fieldParamsTypeStr.equals(ecdsaNSPrefix + ":PrimeFieldParamsType")) + { + fieldParamsType = FIELD_TYPE_PRIME; + String pStr = getChildElementText(fieldParams, ecdsaNS, "P", 1); + p = new BigInteger(pStr, 10); + } + else if (fieldParamsTypeStr.equals(ecdsaNSPrefix + ":TnBFieldParamsType")) + { + fieldParamsType = FIELD_TYPE_TNB; + String mStr = getChildElementText(fieldParams, ecdsaNS, "M", 1); + m = Integer.parseInt(mStr); + String kStr = getChildElementText(fieldParams, ecdsaNS, "K", 1); + k = Integer.parseInt(kStr); + } + else if (fieldParamsTypeStr.equals(ecdsaNSPrefix + ":PnBFieldParamsType")) + { + fieldParamsType = FIELD_TYPE_PNB; + String mStr = getChildElementText(fieldParams, ecdsaNS, "M", 1); + m = Integer.parseInt(mStr); + String k1Str = getChildElementText(fieldParams, ecdsaNS, "K1", 1); + k1 = Integer.parseInt(k1Str); + String k2Str = getChildElementText(fieldParams, ecdsaNS, "K2", 1); + k2 = Integer.parseInt(k2Str); + String k3Str = getChildElementText(fieldParams, ecdsaNS, "K3", 1); + k3 = Integer.parseInt(k3Str); + } + else throw new Exception("Unknown field parameters."); + + // Curve parameters + Element aElem = getChildElement(curveParams, ecdsaNS, "A", 1); + String aStr = aElem.getAttributeNS(null, "Value"); + Element bElem = getChildElement(curveParams, ecdsaNS, "B", 1); + String bStr = bElem.getAttributeNS(null, "Value"); + String seedStr = getChildElementText(curveParams, ecdsaNS, "Seed", 1); + BigInteger seed = (seedStr != null) ? new BigInteger(seedStr, 10) : null; + + // Base point parameters + Element basePoint = getChildElement(basePointParams, ecdsaNS, "BasePoint", 1); + Element basePointXElem = getChildElement(basePoint, ecdsaNS, "X", 1); + String basePointXStr = basePointXElem.getAttributeNS(null, "Value"); + Element basePointYElem = getChildElement(basePoint, ecdsaNS, "Y", 1); + String basePointYStr = basePointYElem.getAttributeNS(null, "Value"); + String orderStr = getChildElementText(basePointParams, ecdsaNS, "Order", 1); + BigInteger order = new BigInteger(orderStr, 10); + String cofactorStr = getChildElementText(basePointParams, ecdsaNS, "Cofactor", 1); + BigInteger cofactor = (cofactorStr != null) ? new BigInteger(cofactorStr, 10) : null; + + if (fieldParamsType == FIELD_TYPE_PRIME) + { + BigInteger a = new BigInteger(aStr, 10); + BigInteger b = new BigInteger(bStr, 10); + BigInteger basePointX = new BigInteger(basePointXStr, 10); + BigInteger basePointY = new BigInteger(basePointYStr, 10); + eccParameterSpec = new ECCParameterSpec(p, cofactor, order, seed, null, a, b, basePointX, + basePointY, null); + } + else + { + int[] irreducible = new int[m/32 + ((m % 32 != 0) ? 1 : 0)]; + if (fieldParamsType == FIELD_TYPE_TNB) + { + irreducible[m/32] = 1 << m % 32; + irreducible[k/32] += 1 << k % 32; + irreducible[0] += 1; + } + else + { + irreducible[m/32] = 1 << m % 32; + irreducible[k3/32] += 1 << k3 % 32; + irreducible[k2/32] += 1 << k2 % 32; + irreducible[k1/32] += 1 << k1 % 32; + irreducible[0] += 1; + } + eccParameterSpec = new ECCParameterSpec(irreducible, cofactor, order, octetString2IntArray(aStr), + octetString2IntArray(bStr), octetString2IntArray(basePointXStr), + octetString2IntArray(basePointYStr), null); + } + } + + // Public key + Element publicKeyElem = getChildElement(keyValueElem, ecdsaNS, "PublicKey", 1); + Element publicKeyXElem = getChildElement(publicKeyElem, ecdsaNS, "X", 1); + String publicKeyXStr = publicKeyXElem.getAttributeNS(null, "Value"); + Element publicKeyYElem = getChildElement(publicKeyElem, ecdsaNS, "Y", 1); + String publicKeyYStr = publicKeyYElem.getAttributeNS(null, "Value"); + + ECDSAParameter ecdsaParams = new ECDSAParameter(eccParameterSpec, false); + ECGroupFactory ecGroupFactory = ECGroupFactory.getInstance(); + EllipticCurve eCurve = ecGroupFactory.getCurveWithProjective(eccParameterSpec.getA(), + eccParameterSpec.getB(), eccParameterSpec.getR()); + Field field = eCurve.getField(); + + // Detect type of public key field elements + String elementType = publicKeyXElem.getAttributeNS(NAMESPACE_XSI, "type"); + String elementTypeLocalName = elementType.substring(elementType.indexOf(':') + 1); + int FIELD_TYPE_PRIME = 1, FIELD_TYPE_CHAR_TWO = 2; + int fieldElemType = ("PrimeFieldElemType".equals(elementTypeLocalName)) + ? FIELD_TYPE_PRIME + : FIELD_TYPE_CHAR_TWO; + + FieldElement publicKeyPointX, publicKeyPointY; + if (fieldElemType == FIELD_TYPE_PRIME) + { + Value xValue = FieldFactory.getInstance().getPrimeFieldValue(new BigInteger(publicKeyXStr, 10)); + publicKeyPointX = field.newElement(xValue); + Value yValue = FieldFactory.getInstance().getPrimeFieldValue(new BigInteger(publicKeyYStr, 10)); + publicKeyPointY = field.newElement(yValue); + } + else + { + publicKeyPointX = field.newElement(octetString2ByteArray(publicKeyXStr)); + publicKeyPointY = field.newElement(octetString2ByteArray(publicKeyYStr)); + } + ProjectiveCoordinate publicKeyPointCoordinate = new ProjectiveCoordinate(publicKeyPointX, + publicKeyPointY, field.getONEelement()); + ECPoint publicKeyPoint = eCurve.newPoint(publicKeyPointCoordinate); + ECPublicKey publicKey = new ECPublicKey(ecdsaParams, publicKeyPoint); + + return publicKey; + } + + /** + * Method getECDSANSPrefix. + * @param element to get the prefix + * @return String the prefix + */ + private static String getECDSANSPrefix(Element element) + { + // FIXXME: Review this function (GK, 11.06.2002) - should return a list of strings, since more than + // one NS prefix can be bound to the ECDSA namespace + + HashMap inScopeNSAttrs = getInScopeNSAttrs(element); + Iterator inScopeNSAttrsIt = inScopeNSAttrs.keySet().iterator(); + while (inScopeNSAttrsIt.hasNext()) + { + Attr currentAttr = (Attr)inScopeNSAttrs.get(inScopeNSAttrsIt.next()); + if (Constants.ECDSA_NS_URI.equals(currentAttr.getValue())) + { + return ("xmlns".equals(currentAttr.getNodeName())) ? "" : currentAttr.getNodeName().substring(6); + } + } + return null; + } + + /** + * Method octetString2IntArray. + * Converts an octet string representation into an int array as needed for the IAIK ECC library + * @param octetString rightmost byte is least significant byte + * @return int[] rightmost byte is LEAST significant byte + */ + private static int[] octetString2IntArray(String octetString) + { + int byteCount = octetString.length()/2; + int[] intArray = new int[byteCount/4 + ((byteCount % 4 != 0) ? 1 : 0)]; + for (int i = 0; i < byteCount; i++) + { + int oSStartPos = octetString.length() - (i + 1) * 2; + int currentByte = Integer.parseInt(octetString.substring(oSStartPos, oSStartPos + 2), 16); + intArray[i/4] += (currentByte & 0xFF) << ((i % 4) * 8); + } + return intArray; + } + + /** + * Converts an octet string representation into a byte array as needed for the IAIK ECC library + * @param octetString rightmost byte is least significant byte + * @return byte[] rightmost byte is MOST significant byte + */ + private static byte[] octetString2ByteArray(String octetString) + { + int byteCount = octetString.length()/2; + byte[] byteArray = new byte[byteCount]; + for (int i = 0; i < byteCount; i++) + { + int oSStartPos = octetString.length() - (i + 1) * 2; + byteArray[byteCount - i - 1] = (byte) Integer.parseInt(octetString.substring( + oSStartPos, oSStartPos + 2), 16); + } + return byteArray; + } + + /** + * Method evenStringLength. + * @param hexString + * @return String + */ + + private static String evenStringLength(String hexString) + { + return (hexString.length() % 2 != 0) ? "0" + hexString : hexString; + } + + /** + * Method getChildElement. + * @param parent + * @param namespace + * @param localName + * @param instance + * @return Element + */ + + private static Element getChildElement(Element parent, String namespace, String localName, + int instance) + { + NodeList namedElements = parent.getElementsByTagNameNS(namespace, localName); + if (namedElements.getLength() < instance) return null; + return (Element)namedElements.item(instance - 1); + } + + /** + * Method getChildElementText. + * @param parent Element + * @param namespace String + * @param localName String + * @param instance int + * @return String + */ + + private static String getChildElementText(Element parent, String namespace, String localName, + int instance) + { + Element child = getChildElement(parent, namespace, localName, instance); + if (child == null) return null; + NodeList childNodes = child.getChildNodes(); + int nodeCount = 0; + while (nodeCount < childNodes.getLength()) + { + Node currentNode = childNodes.item(nodeCount); + if (currentNode.getNodeType() == Node.TEXT_NODE) return currentNode.getNodeValue(); + nodeCount++; + } + return null; + } + + /** + * Method getInScopeNSAttrs. + * @param element element + * @return HashMap + */ + public static HashMap getInScopeNSAttrs(Element element) + { + // Get all ancestors of element + Vector ancestors = new Vector(); + ancestors.add(element); + Node currentAncestor = element; + while ((currentAncestor = currentAncestor.getParentNode()) != null && + currentAncestor.getNodeType() == Node.ELEMENT_NODE) + { + ancestors.add(currentAncestor); + } + + // Scan all ancestors for NS attributes + HashMap inScopeNSAttrs = new HashMap(); + for (int i = ancestors.size() - 1; i >= 0; i--) + { + Element currentAncestorElem = (Element)ancestors.get(i); + NamedNodeMap attrs = currentAncestorElem.getAttributes(); + for (int j = 0; j < attrs.getLength(); j++) + { + Attr currentAttr = (Attr)attrs.item(j); + String currentAttrName = currentAttr.getNodeName(); + if ("xmlns".equals(currentAttrName) || currentAttrName.startsWith("xmlns:")) + { + inScopeNSAttrs.put(currentAttrName, currentAttr); + } + } + } + + // Check if default NS attribute is in list; if value is empty remove it from list + Attr defaultNSAttr = (Attr)inScopeNSAttrs.get("xmlns"); + if (defaultNSAttr != null && "".equals(defaultNSAttr.getValue())) inScopeNSAttrs.remove("xmlns"); + + return inScopeNSAttrs; + } +} \ No newline at end of file -- cgit v1.2.3