Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial import.

  • Loading branch information...
commit 36eff388595e4645b963abc4b50354b84fe458dd 0 parents
@ruseel authored
8 .gitignore
@@ -0,0 +1,8 @@
+target/
+lq.rvalue
+out.der
+result.xml
+.classpath
+.project
+.settings/
+
63 pom.xml
@@ -0,0 +1,63 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.barostudio</groupId>
+ <artifactId>kr-etax-sample</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>kr-etax-sample</name>
+ <dependencies>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpmime</artifactId>
+ <version>4.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.santuario</groupId>
+ <artifactId>xmlsec</artifactId>
+ <version>1.5.2</version>
+ </dependency>
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <version>1.47</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <version>1.47</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>1.4</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.5.1</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
86 src/main/java/com/barostudio/EncryptWithCMS.java
@@ -0,0 +1,86 @@
+package com.barostudio;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.cms.CMSAlgorithm;
+import org.bouncycastle.cms.CMSEnvelopedData;
+import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSTypedData;
+import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
+import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import com.barostudio.nts.asn1.TaxInvoiceData;
+import com.barostudio.nts.asn1.TaxInvoicePackage;
+
+public class EncryptWithCMS {
+
+ public static void main(String[] args) throws Exception {
+ String rvaluefile = args[0];
+ String xmlfile = args[1];
+ String encryptedFile = args[2];
+
+ byte[] _package = getTaxInvoicePackageAsBytes(rvaluefile, xmlfile);
+ CMSTypedData msg = new CMSProcessableByteArray(_package);
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(
+ kmCert("src/main/resources/KmCert.der")).setProvider("BC"));
+
+ CMSEnvelopedData ed = edGen.generate(msg,
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)
+ .setProvider("BC").build());
+ byte[] cmsEncryptedBytes = ed.getEncoded();
+
+ FileOutputStream out = new FileOutputStream(encryptedFile);
+ out.write(cmsEncryptedBytes);
+ out.close();
+ }
+
+ public static byte[] getTaxInvoicePackageAsBytes(String rvaluefile, String xmlfile) throws Exception {
+ byte[] signerRvalue = readAll(rvaluefile);
+ byte[] taxInvoice = readAll(xmlfile);
+ TaxInvoiceData data = new TaxInvoiceData(signerRvalue, taxInvoice);
+
+ TaxInvoicePackage pkg = new TaxInvoicePackage(new TaxInvoiceData[] { data });
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ DEROutputStream out = new DEROutputStream(baos);
+ out.writeObject(pkg);
+ out.close();
+
+ return baos.toByteArray();
+ }
+
+ public static byte[] readAll(String file) throws Exception {
+ InputStream in = new FileInputStream(file);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int numRead;
+ while ((numRead = in.read(buffer)) >= 0) {
+ baos.write(buffer, 0, numRead);
+ }
+ return baos.toByteArray();
+ }
+
+ private static X509Certificate kmCert(String nipaTestCert) throws FileNotFoundException, CertificateException {
+ Security.addProvider(new BouncyCastleProvider());
+
+ FileInputStream ksfis = new FileInputStream(nipaTestCert);
+ BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
+ X509Certificate certificate = (X509Certificate)
+ CertificateFactory.getInstance("X.509").generateCertificate(ksbufin);
+ return certificate;
+ }
+}
35 src/main/java/com/barostudio/LoadPKCS12.java
@@ -0,0 +1,35 @@
+package com.barostudio;
+
+import java.io.FileInputStream;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class LoadPKCS12 {
+
+ @SuppressWarnings("rawtypes")
+ public static void main(String[] args) throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+
+ KeyStore ks = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
+ char[] password = args[1].toCharArray();
+ ks.load(new FileInputStream(args[0]), password);
+
+ Enumeration e=ks.aliases();
+ if (!e.hasMoreElements()) {
+ throw new RuntimeException("No aliases");
+ }
+ String alias = (String)e.nextElement();
+
+ PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password);
+ X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
+
+ System.out.println(privateKey);
+ System.out.println(cert);
+ }
+
+}
23 src/main/java/com/barostudio/MultipartRelatedEntity.java
@@ -0,0 +1,23 @@
+package com.barostudio;
+
+import java.nio.charset.Charset;
+
+import org.apache.http.entity.mime.MultipartEntity;
+
+class MultipartRelatedEntity extends MultipartEntity {
+ @Override
+ protected String generateContentType(String boundary, Charset charset) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("multipart/related");
+ buffer.append("; type=\"text/xml\"");
+ buffer.append("; start=\"<SOAPPart>\"");
+ buffer.append("; boundary=\"");
+ buffer.append(boundary);
+ buffer.append("\"");
+ if (charset != null) {
+ buffer.append("; charset=");
+ buffer.append(charset.name());
+ }
+ return buffer.toString();
+ }
+}
40 src/main/java/com/barostudio/PackageTaxInvoice.java
@@ -0,0 +1,40 @@
+package com.barostudio;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+
+import org.bouncycastle.asn1.DEROutputStream;
+
+import com.barostudio.nts.asn1.TaxInvoiceData;
+import com.barostudio.nts.asn1.TaxInvoicePackage;
+
+public class PackageTaxInvoice {
+
+ public static void main(String[] args) throws Exception {
+ String rvalueFile = args[0];
+ String signedXMLFile = args[1];
+ String derOutFile = args[2];
+
+ TaxInvoicePackage pkg = new TaxInvoicePackage(new TaxInvoiceData[] {
+ new TaxInvoiceData(readAll(rvalueFile), readAll(signedXMLFile))
+ });
+
+ DEROutputStream out = new DEROutputStream(new FileOutputStream(derOutFile));
+ out.writeObject(pkg);
+ out.close();
+ }
+
+ public static byte[] readAll(String file) throws Exception {
+ InputStream in = new FileInputStream(file);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int numRead;
+ while ((numRead = in.read(buffer)) >= 0) {
+ baos.write(buffer, 0, numRead);
+ }
+ return baos.toByteArray();
+ }
+
+}
531 src/main/java/com/barostudio/SaveRvalue.java
@@ -0,0 +1,531 @@
+package com.barostudio;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERBMPString;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.pkcs.Attribute;
+import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
+import org.bouncycastle.asn1.pkcs.ContentInfo;
+import org.bouncycastle.asn1.pkcs.EncryptedData;
+import org.bouncycastle.asn1.pkcs.MacData;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import org.bouncycastle.asn1.pkcs.Pfx;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.SafeBag;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.provider.JDKPKCS12KeyStore;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+
+public class SaveRvalue {
+
+ public static void main(String[] args) throws Exception {
+ String p12file = args[0];
+ String p12password = args[1];
+ String rvalueOutFile = args[2];
+
+ CustomPKCS12KeyStore ks = new CustomPKCS12KeyStore();
+ ks.engineLoad(new FileInputStream(p12file), p12password.toCharArray());
+
+ OutputStream out = new FileOutputStream(rvalueOutFile);
+ out.write(ks.getRvalue());
+ }
+
+
+ static class CustomPKCS12KeyStore extends JDKPKCS12KeyStore {
+ @SuppressWarnings("rawtypes")
+ private Hashtable localIds;
+ private IgnoresCaseHashtable keys;
+ private byte[] rvalue;
+
+ public CustomPKCS12KeyStore() {
+ super(null, null, null);
+ }
+
+ public byte[] getRvalue() {
+ return rvalue;
+ }
+
+ @SuppressWarnings({ "rawtypes", "deprecation", "unchecked", "unused" })
+ public void engineLoad(InputStream stream, char[] password)
+ throws IOException {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null) {
+ throw new NullPointerException(
+ "No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30) {
+ throw new IOException(
+ "stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence) bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString) info.getContent()).getOctets();
+
+ try {
+ byte[] res = calculatePbeMac(algId.getObjectId(), salt,
+ itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig)) {
+ if (password.length > 0) {
+ throw new IOException(
+ "PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getObjectId(), salt,
+ itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig)) {
+ throw new IOException(
+ "PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ } catch (IOException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new IOException("error constructing MAC: "
+ + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data)) {
+ bIn = new ASN1InputStream(
+ ((ASN1OctetString) info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn
+ .readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++) {
+ if (c[i].getContentType().equals(data)) {
+ ASN1InputStream dIn = new ASN1InputStream(
+ ((ASN1OctetString) c[i].getContent())
+ .getOctets());
+ ASN1Sequence seq = (ASN1Sequence) dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++) {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag)) {
+ org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo
+ .getInstance(b.getBagValue());
+
+ PrivateKey privKey = unwrapXXKey(
+ eIn.getEncryptionAlgorithm(),
+ eIn.getEncryptedData(), password,
+ wrongPKCS12Zero);
+
+ System.out.println("privKey: " + privKey);
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null) {
+ Enumeration e = b.getBagAttributes()
+ .getObjects();
+ while (e.hasMoreElements()) {
+ ASN1Sequence sq = (ASN1Sequence) e
+ .nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier) sq
+ .getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set) sq
+ .getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0) {
+ attr = (ASN1Primitive) attrSet
+ .getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr
+ .getBagAttribute(aOid);
+ if (existing != null) {
+ // OK, but the value has to be
+ // the same
+ if (!existing.toASN1Primitive()
+ .equals(attr)) {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ } else {
+ bagAttr.setBagAttribute(aOid,
+ attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName)) {
+ alias = ((DERBMPString) attr)
+ .getString();
+ keys.put(alias, privKey);
+ } else if (aOid
+ .equals(pkcs_9_at_localKeyId)) {
+ localId = (ASN1OctetString) attr;
+ }
+ }
+ }
+
+ if (localId != null) {
+ String name = new String(Hex.encode(localId
+ .getOctets()));
+
+ if (alias == null) {
+ keys.put(name, privKey);
+ } else {
+ localIds.put(alias, name);
+ }
+ } else {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ } else if (b.getBagId().equals(certBag)) {
+ chain.addElement(b);
+ } else {
+ System.out.println("extra in data "
+ + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ } else if (c[i].getContentType().equals(encryptedData)) {
+ System.out.println("encryptedData");
+ EncryptedData d = EncryptedData.getInstance(c[i]
+ .getContent());
+ byte[] octets = cryptData(false,
+ d.getEncryptionAlgorithm(), password,
+ wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence) ASN1Primitive
+ .fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++) {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag)) {
+ chain.addElement(b);
+ } else if (b.getBagId().equals(pkcs8ShroudedKeyBag)) {
+ org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo
+ .getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(
+ eIn.getEncryptionAlgorithm(),
+ eIn.getEncryptedData(), password,
+ wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes()
+ .getObjects();
+ while (e.hasMoreElements()) {
+ ASN1Sequence sq = (ASN1Sequence) e
+ .nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier) sq
+ .getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set) sq
+ .getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0) {
+ attr = (ASN1Primitive) attrSet
+ .getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr
+ .getBagAttribute(aOid);
+ if (existing != null) {
+ // OK, but the value has to be the
+ // same
+ if (!existing.toASN1Primitive()
+ .equals(attr)) {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ } else {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName)) {
+ alias = ((DERBMPString) attr)
+ .getString();
+ keys.put(alias, privKey);
+ } else if (aOid
+ .equals(pkcs_9_at_localKeyId)) {
+ localId = (ASN1OctetString) attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId
+ .getOctets()));
+
+ if (alias == null) {
+ keys.put(name, privKey);
+ } else {
+ localIds.put(alias, name);
+ }
+ } else if (b.getBagId().equals(keyBag)) {
+ org.bouncycastle.asn1.pkcs.PrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.PrivateKeyInfo(
+ (ASN1Sequence) b.getBagValue());
+ System.out.println("kInfo: " + kInfo);
+ PrivateKey privKey = BouncyCastleProvider
+ .getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier) privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ Enumeration e = b.getBagAttributes()
+ .getObjects();
+ while (e.hasMoreElements()) {
+ ASN1Sequence sq = (ASN1Sequence) e
+ .nextElement();
+ ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier) sq
+ .getObjectAt(0);
+ ASN1Set attrSet = (ASN1Set) sq
+ .getObjectAt(1);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0) {
+ attr = (ASN1Primitive) attrSet
+ .getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr
+ .getBagAttribute(aOid);
+ if (existing != null) {
+ // OK, but the value has to be the
+ // same
+ if (!existing.toASN1Primitive()
+ .equals(attr)) {
+ throw new IOException(
+ "attempt to add existing attribute with different value");
+ }
+ } else {
+ bagAttr.setBagAttribute(aOid, attr);
+ }
+ }
+
+ if (aOid.equals(pkcs_9_at_friendlyName)) {
+ alias = ((DERBMPString) attr)
+ .getString();
+ keys.put(alias, privKey);
+ } else if (aOid
+ .equals(pkcs_9_at_localKeyId)) {
+ localId = (ASN1OctetString) attr;
+ }
+ }
+
+ String name = new String(Hex.encode(localId
+ .getOctets()));
+
+ if (alias == null) {
+ keys.put(name, privKey);
+ } else {
+ localIds.put(alias, name);
+ }
+ } else {
+ System.out.println("extra in encryptedData "
+ + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ } else {
+ System.out.println("extra "
+ + c[i].getContentType().getId());
+ System.out.println("extra "
+ + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ }
+
+ protected PrivateKey unwrapXXKey(AlgorithmIdentifier algId, byte[] data,
+ char[] password, boolean wrongPKCS12Zero) throws IOException {
+ String algorithm = algId.getAlgorithm().getId();
+ System.out.println(algorithm);
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId
+ .getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ try {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm,
+ bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(), pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey) k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this
+ // point
+ out = (PrivateKey) cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+
+
+ // ´Ù½Ã decrypt Çؼ­ PrivateKeyInfo¸¦ °¡Á®¿Íº»´Ù
+ cipher.init(Cipher.DECRYPT_MODE, k, defParams);
+ PrivateKeyInfo in = PrivateKeyInfo.getInstance(cipher.doFinal(data));
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in);
+
+ System.out.println("Shoud be equal: " + out.equals(privKey));
+
+ ASN1Set set = in.getAttributes();
+ Attribute attribute = Attribute.getInstance(set.getObjectAt(0));
+ ASN1Encodable rValueAsASNEncodable = attribute.getAttributeValues()[0];
+ rvalue = ((DERBitString)rValueAsASNEncodable).getBytes();
+ } catch (Exception e) {
+ throw new IOException("exception unwrapping private key - "
+ + e.toString());
+ }
+
+ return out;
+ }
+
+ }
+
+
+ public static Provider bcProvider = new BouncyCastleProvider();
+
+ private static byte[] calculatePbeMac(ASN1ObjectIdentifier oid,
+ byte[] salt, int itCount, char[] password, boolean wrongPkcs12Zero,
+ byte[] data) throws Exception {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(),
+ bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
+ key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
+
+ Mac mac = Mac.getInstance(oid.getId(), bcProvider);
+ mac.init(key, defParams);
+ mac.update(data);
+ return mac.doFinal();
+ }
+
+ private static class IgnoresCaseHashtable {
+ @SuppressWarnings("rawtypes")
+ private Hashtable orig = new Hashtable();
+ @SuppressWarnings("rawtypes")
+ private Hashtable keys = new Hashtable();
+
+ @SuppressWarnings("unchecked")
+ public void put(String key, Object value) {
+ String lower = Strings.toLowerCase(key);
+ String k = (String) keys.get(lower);
+ if (k != null) {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unused" })
+ public Enumeration keys() {
+ return orig.keys();
+ }
+
+ @SuppressWarnings("unused")
+ public Object remove(String alias) {
+ String k = (String) keys.remove(Strings.toLowerCase(alias));
+ if (k == null) {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ @SuppressWarnings("unused")
+ public Object get(String alias) {
+ String k = (String) keys.get(Strings.toLowerCase(alias));
+ if (k == null) {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ @SuppressWarnings({ "rawtypes", "unused" })
+ public Enumeration elements() {
+ return orig.elements();
+ }
+ }
+
+}
102 src/main/java/com/barostudio/SignXML.java
@@ -0,0 +1,102 @@
+package com.barostudio;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.xml.security.signature.XMLSignature;
+import org.apache.xml.security.transforms.Transforms;
+import org.apache.xml.security.utils.Constants;
+import org.apache.xml.security.utils.XMLUtils;
+import org.apache.xpath.XPathAPI;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public class SignXML {
+
+ private static PrivateKey privateKey;
+ private static X509Certificate cert;
+
+ public static void main(String[] args) throws Exception {
+ String p12file = args[0];
+ String p12password = args[1];
+ String inputXML = args[2];
+ String outputXML = args[3];
+
+ loadPrivateKeyAndCertificates(p12file, p12password);
+ sign(privateKey, cert, new FileInputStream(inputXML), new FileOutputStream(outputXML));
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static void loadPrivateKeyAndCertificates(String p12file, String p12password) throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+
+ KeyStore ks = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
+ char[] password = p12password.toCharArray();
+ ks.load(new FileInputStream(p12file), password);
+
+ Enumeration e=ks.aliases();
+ if (!e.hasMoreElements()) {
+ throw new RuntimeException("No aliases");
+ }
+ String alias = (String)e.nextElement();
+
+ privateKey = (PrivateKey) ks.getKey(alias, password);
+ cert = (X509Certificate) ks.getCertificate(alias);
+ }
+
+
+ public static void sign(PrivateKey privateKey, X509Certificate cert, InputStream is, OutputStream os)
+ throws Exception {
+ org.apache.xml.security.Init.init();
+
+ // Document 만들기
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(is);
+
+ // XMLSignature 객체를 만들고
+ String BaseURI = "";
+ XMLSignature sig = new XMLSignature(doc, BaseURI,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
+ // 그 객체안의 W3C Element를 DOM안에 삽입
+ {
+ Element ctx = doc.createElementNS(null, "namespaceContext");
+ ctx.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:tax", "urn:kr:or:kec:standard:Tax:ReusableAggregateBusinessInformationEntitySchemaModule:1:0");
+ Node pivot = XPathAPI.selectSingleNode(doc, "//tax:TaxInvoiceDocument", ctx);
+ pivot.getParentNode().insertBefore(sig.getElement(), pivot);
+ }
+
+ //create the transforms object for the Document/Reference
+ {
+ Transforms transforms = new Transforms(doc);
+ transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
+
+ Element xpathElement = doc.createElementNS("http://www.w3.org/2000/09/xmldsig#", "ds:XPath");
+ xpathElement.appendChild(doc.createTextNode("not(self::*[name() = 'TaxInvoice'] | ancestor-or-self::*[name() = 'ExchangedDocument'] | ancestor-or-self::ds:Signature)"));
+ transforms.addTransform(Transforms.TRANSFORM_XPATH, xpathElement);
+
+ sig.addDocument("", transforms, DigestMethod.SHA256);
+ }
+
+ // XMLSignature에 공개키 추가하고 서명
+ sig.addKeyInfo(cert);
+ sig.sign(privateKey);
+
+ // OutputStream으로 document를 String으로 변환 출력
+ XMLUtils.outputDOMc14nWithComments(doc, os);
+ }
+}
312 src/main/java/com/barostudio/SubmitWithSOAP.java
@@ -0,0 +1,312 @@
+package com.barostudio;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.namespace.QName;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPBody;
+import javax.xml.soap.SOAPElement;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPHeaderElement;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.soap.SOAPPart;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.mime.FormBodyPart;
+import org.apache.http.entity.mime.MultipartEntity;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.signature.XMLSignature;
+import org.apache.xml.security.transforms.Transforms;
+import org.apache.xml.security.utils.Base64;
+import org.apache.xml.security.utils.Constants;
+import org.apache.xml.security.utils.XMLUtils;
+import org.apache.xml.security.utils.resolver.ResourceResolver;
+import org.apache.xpath.XPathAPI;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.barostudio.nts.ext.ResolverOwnerDocumentUserData;
+import com.barostudio.nts.ext.TransformAttachementContentSignature;
+
+public class SubmitWithSOAP {
+ public static final String wssswa = "http://docs.oasis-open.org/wss/oasis-wss-SwAProfile-1.1#Attachment-Content-Signature-Transform";
+
+ private static PrivateKey privateKey;
+ private static X509Certificate cert;
+
+ public static void main(String[] args) throws Exception {
+ System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.SimpleLog");
+ System.setProperty("org.apache.commons.logging.simplelog.showdatetime", "true");
+ System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http", "debug");
+ System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.http.wire", "debug");
+ System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.xml.security.utils", "debug");
+ System.setProperty("org.apache.commons.logging.simplelog.log.org.apache.xml.security.utils.DigesterOutputStream", "debug");
+
+ String p12file = args[0];
+ String p12password = args[1];
+ String cmsEncryptedFile = args[2];
+ String endPoint = args[3];
+
+ org.apache.xml.security.Init.init();
+ org.apache.xml.security.transforms.Transform.register(wssswa, TransformAttachementContentSignature.class);
+ ResourceResolver.register(new ResolverOwnerDocumentUserData(), false);
+
+ loadPrivateKeyAndCertificates(p12file, p12password);
+ byte[] taxInvoiceBlob = readAll(cmsEncryptedFile);
+
+ SOAPMessage message = buildMessage(endPoint);
+ signMessage(message, taxInvoiceBlob);
+
+ Element document = message.getSOAPPart().getDocumentElement();
+ submitWithSOAP(document, endPoint, cmsEncryptedFile);
+ }
+
+ @SuppressWarnings("rawtypes")
+ private static void loadPrivateKeyAndCertificates(String p12file, String p12password) throws Exception {
+ Security.addProvider(new BouncyCastleProvider());
+
+ KeyStore ks = KeyStore.getInstance("PKCS12", BouncyCastleProvider.PROVIDER_NAME);
+ char[] password = p12password.toCharArray();
+ ks.load(new FileInputStream(p12file), password);
+
+ Enumeration e=ks.aliases();
+ if (!e.hasMoreElements()) {
+ throw new RuntimeException("No aliases");
+ }
+ String alias = (String)e.nextElement();
+
+ privateKey = (PrivateKey) ks.getKey(alias, password);
+ cert = (X509Certificate) ks.getCertificate(alias);
+ }
+
+
+ public static SOAPMessage buildMessage(String endPoint) throws SOAPException, Exception {
+ MessageFactory factory = MessageFactory.newInstance();
+ SOAPMessage message = factory.createMessage();
+
+ SOAPHeader header = message.getSOAPHeader();
+ SOAPPart part = message.getSOAPPart();
+ SOAPEnvelope en = part.getEnvelope();
+ SOAPBody body = message.getSOAPBody();
+ SOAPHeader soapHeader = en.getHeader();
+ if (soapHeader == null) {
+ soapHeader = en.addHeader();
+ }
+
+ en.addNamespaceDeclaration("ds", "http://www.w3.org/2000/09/xmldsig#");
+ en.addNamespaceDeclaration("kec", "http://www.kec.or.kr/standard/Tax/");
+ en.addNamespaceDeclaration("wsa",
+ "http://www.w3.org/2005/08/addressing");
+ en.addNamespaceDeclaration(
+ "wsse",
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
+ en.addNamespaceDeclaration(
+ "wsu",
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
+ en.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
+ en.addNamespaceDeclaration("xsi",
+ "http://www.w3.org/2001/XMLSchema-instance");
+
+ soapHeader.addChildElement("MessageID", "wsa").addTextNode(
+ "20091013112725078-b9127eac9173494dab9ff31f57c84587");
+ soapHeader.addChildElement("To", "wsa").addTextNode(endPoint);
+ soapHeader.addChildElement("Action", "wsa").addTextNode(
+ "http://www.kec.or.kr/standard/Tax/TaxInvoiceSubmit");
+
+ SOAPElement kecMessageHeader = soapHeader.addChildElement(
+ "MessageHeader", "kec");
+ kecMessageHeader.addChildElement("Version", "kec").addTextNode("3.0");
+ SOAPElement from = kecMessageHeader.addChildElement("From", "kec");
+ from.addChildElement("PartyID", "kec").addTextNode("2208203228");
+ from.addChildElement("PartyName", "kec").addTextNode(
+ "National IT Industry Promotion Agency");
+ SOAPElement to = kecMessageHeader.addChildElement("To", "kec");
+ to.addChildElement("PartyID", "kec").addTextNode("9999999999");
+ to.addChildElement("PartyName", "kec").addTextNode(
+ "National Tax Service");
+
+ kecMessageHeader.addChildElement("ReplyTo", "kec").addTextNode(
+ "http://www.nipa.or.kr/etax/SendResultsService");
+ kecMessageHeader.addChildElement("OperationType", "kec").addTextNode(
+ "01");
+ kecMessageHeader.addChildElement("MessageType", "kec")
+ .addTextNode("01");
+ kecMessageHeader.addChildElement("TimeStamp", "kec").addTextNode(
+ "2009-10-13T14:27:25.109Z");
+
+ SOAPHeaderElement security = soapHeader
+ .addHeaderElement(new QName(
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
+ "Security"));
+ SOAPElement bst = security
+ .addChildElement(new QName(
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
+ "BinarySecurityToken"));
+ bst.setAttribute(
+ "EncodingType",
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
+ bst.setAttribute(
+ "ValueType",
+ "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#X509v3");
+ bst.setAttribute("wsu:Id", "X509Token");
+ bst.addTextNode(Base64.encode(cert.getEncoded()));
+
+
+ SOAPElement requestMessage = body.addChildElement("RequestMessage", "kec");
+ requestMessage.addChildElement("SubmitID", "kec").addTextNode("12345678-20120904-0123456789abcdef0123456789abcdef");
+ requestMessage.addChildElement("TotalCount", "kec").addTextNode("5");
+ requestMessage.addChildElement("ReferenceID", "kec").addTextNode("taxInvoicePart");
+
+ return message;
+ }
+
+ private static void signMessage(SOAPMessage message, byte[] taxInvoiceBlob) throws Exception {
+ SOAPPart part = message.getSOAPPart();
+ SOAPEnvelope en = part.getEnvelope();
+
+ String BaseURI = "";
+ Document doc = (Document)en.getOwnerDocument();
+ XMLSignature sig = new XMLSignature(doc, BaseURI,
+ XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256);
+
+ {
+ KeyInfo keyinfo = sig.getKeyInfo();
+ Element keyinfoEl = keyinfo.getElement();
+ Element securityTokenReference = doc.createElementNS(en.getNamespaceURI("wsse"), "wsse:SecurityTokenReference");
+ Element ref = doc.createElementNS(en.getNamespaceURI("wsse"), "wsse:Reference");
+ ref.setAttribute("URI", "#X509Token");
+ securityTokenReference.appendChild(ref);
+ keyinfoEl.appendChild(securityTokenReference);
+ }
+
+ {
+ Transforms transforms = new Transforms(doc);
+ transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
+ transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
+ sig.addDocument("", transforms, DigestMethod.SHA256);
+ }
+
+ doc.setUserData("cid:taxInvoicePart", taxInvoiceBlob, null);
+
+ Transforms transforms = new Transforms(doc);
+ transforms.addTransform(wssswa);
+ sig.addDocument("cid:taxInvoicePart", transforms, DigestMethod.SHA256);
+
+ // Security¾Æ·¡¿¡ ds:Signature »ðÀÔ
+ {
+ Element ctx = doc.createElementNS(null, "namespaceContext");
+ ctx.setAttributeNS(Constants.NamespaceSpecNS, "xmlns:wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
+ Node pivot = XPathAPI.selectSingleNode(doc, "//wsse:Security", ctx);
+ pivot.appendChild(sig.getElement());
+ }
+
+ sig.sign(privateKey);
+ }
+
+ private static void submitWithSOAP(Element document, String endPoint, String cmsEncryptedFile)
+ throws TransformerFactoryConfigurationError,
+ Exception {
+ String xmlAsString = asString(document);
+ File taxInvoiceIS = new File(cmsEncryptedFile);
+
+ HttpPost soapPost = new HttpPost(endPoint);
+ MultipartEntity multipartEntity = new MultipartRelatedEntity();
+
+ FormBodyPart xmlPart = new FormBodyPart("soap-req", new StringBody(xmlAsString, "text/xml", Charset.forName("UTF-8")));
+ xmlPart.addField("Content-ID", "<SOAPPart>");
+ multipartEntity.addPart(xmlPart);
+
+ FormBodyPart taxInvoicePart = new FormBodyPart("taxinvoice", new FileBody(taxInvoiceIS));
+ taxInvoicePart.addField("Content-ID", "<taxInvoicePart>");
+ multipartEntity.addPart(taxInvoicePart);
+
+ soapPost.setEntity(multipartEntity);
+ soapPost.addHeader("Soapaction", "\"\"");
+ soapPost.addHeader("Accept", "text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
+
+
+ DefaultHttpClient httpclient = new DefaultHttpClient();
+ HttpResponse response = httpclient.execute(soapPost);
+ System.out.println(response.getStatusLine());
+
+ HttpEntity entity = response.getEntity();
+ InputStream is = entity.getContent();
+ BufferedReader r = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
+ String line;
+ while ((line = r.readLine()) != null) {
+ System.out.println(line);
+ }
+
+
+ EntityUtils.consume(entity);
+
+ try { httpclient.getConnectionManager().shutdown(); } catch (Exception ignore) {}
+ }
+
+ @SuppressWarnings("unused")
+ private static String asString(Element el)
+ throws TransformerFactoryConfigurationError,
+ TransformerConfigurationException, TransformerException, Exception {
+ String blob;
+ if (false) {
+ javax.xml.transform.TransformerFactory tfactory = TransformerFactory
+ .newInstance();
+ javax.xml.transform.Transformer xform = tfactory.newTransformer();
+ javax.xml.transform.Source src = new DOMSource(el);
+ xform.setOutputProperty(OutputKeys.INDENT, "yes");
+ xform.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
+ "4");
+ java.io.StringWriter writer = new StringWriter();
+ Result result = new javax.xml.transform.stream.StreamResult(writer);
+ xform.transform(src, result);
+ blob = writer.toString();
+ } else {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ XMLUtils.outputDOMc14nWithComments(el, baos);
+ blob = baos.toString("UTF-8");
+ }
+ return blob;
+ }
+
+ public static byte[] readAll(String file) throws Exception {
+ InputStream in = new FileInputStream(file);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int numRead;
+ while ((numRead = in.read(buffer)) >= 0) {
+ baos.write(buffer, 0, numRead);
+ }
+ return baos.toByteArray();
+ }
+
+}
47 src/main/java/com/barostudio/nts/asn1/TaxInvoiceData.java
@@ -0,0 +1,47 @@
+package com.barostudio.nts.asn1;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+@SuppressWarnings("rawtypes")
+public class TaxInvoiceData extends ASN1Object {
+ /**
+ * TaxIvnoiceData ::= SEQUENCE {
+ * rvalue SignerRvalue,
+ * taxInvoice TaxInvoice }
+ */
+ public ASN1OctetString signerRvalue;
+ public ASN1OctetString taxInvoice;
+
+ public static TaxInvoiceData getInstance(Object obj) {
+ return new TaxInvoiceData(ASN1Sequence.getInstance(obj));
+ }
+
+ public TaxInvoiceData(ASN1Sequence seq) {
+ Enumeration e = seq.getObjects();
+ signerRvalue = ASN1OctetString.getInstance(e.nextElement());
+ taxInvoice = ASN1OctetString.getInstance(e.nextElement());
+ }
+
+ public TaxInvoiceData(byte[] signerRvalue, byte[] taxInvoice) {
+ this.signerRvalue = new DEROctetString(signerRvalue);
+ this.taxInvoice = new DEROctetString(taxInvoice);
+ }
+
+ @Override
+ public ASN1Primitive toASN1Primitive() {
+ ASN1EncodableVector seq = new ASN1EncodableVector();
+ seq.add(signerRvalue);
+ seq.add(taxInvoice);
+
+ return new DERSequence(seq);
+ }
+
+}
57 src/main/java/com/barostudio/nts/asn1/TaxInvoicePackage.java
@@ -0,0 +1,57 @@
+package com.barostudio.nts.asn1;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+
+@SuppressWarnings("rawtypes")
+public class TaxInvoicePackage extends ASN1Object {
+
+ /**
+ * TaxInvoicePackage ::= SEQUENCE {
+ * count InvoiceCount,
+ * taxInvoiceSet TaxInvoiceSet }
+ *
+ * InvoiceCount ::= INTEGER
+ * TaxInvoiceSet ::= SET SIZE (1..100) OF TaxInvoiceData
+ */
+
+ public BigInteger count;
+ public ASN1Set taxInvoiceSet;
+
+ public TaxInvoicePackage(ASN1Sequence seq) {
+ Enumeration e = seq.getObjects();
+
+ count = ((ASN1Integer)e.nextElement()).getValue();
+ taxInvoiceSet = (ASN1Set)e.nextElement();
+ }
+
+ public TaxInvoicePackage(TaxInvoiceData[] taxInvoices) {
+ count = BigInteger.valueOf(taxInvoices.length);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i=0; i<taxInvoices.length; i++)
+ v.add(taxInvoices[i]);
+
+ taxInvoiceSet = ASN1Set.getInstance(new DERSet(v));
+ }
+
+ @Override
+ public ASN1Primitive toASN1Primitive() {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERInteger(count));
+ v.add(taxInvoiceSet);
+
+ return new DERSequence(v);
+ }
+}
23 src/main/java/com/barostudio/nts/ext/MultipartRelatedEntity.java
@@ -0,0 +1,23 @@
+package com.barostudio.nts.ext;
+
+import java.nio.charset.Charset;
+
+import org.apache.http.entity.mime.MultipartEntity;
+
+public class MultipartRelatedEntity extends MultipartEntity {
+ @Override
+ protected String generateContentType(String boundary, Charset charset) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append("multipart/related");
+ buffer.append("; type=\"text/xml\"");
+ buffer.append("; start=\"<SOAPPart>\"");
+ buffer.append("; boundary=\"");
+ buffer.append(boundary);
+ buffer.append("\"");
+ if (charset != null) {
+ buffer.append("; charset=");
+ buffer.append(charset.name());
+ }
+ return buffer.toString();
+ }
+}
36 src/main/java/com/barostudio/nts/ext/ResolverOwnerDocumentUserData.java
@@ -0,0 +1,36 @@
+package com.barostudio.nts.ext;
+
+import org.apache.xml.security.signature.XMLSignatureInput;
+import org.apache.xml.security.utils.resolver.ResourceResolverException;
+import org.apache.xml.security.utils.resolver.ResourceResolverSpi;
+import org.w3c.dom.Attr;
+
+public class ResolverOwnerDocumentUserData extends ResourceResolverSpi {
+ @Override
+ public XMLSignatureInput engineResolve(Attr uri, String baseURI)
+ throws ResourceResolverException {
+ byte[] x = (byte[]) uri.getOwnerDocument().getUserData(uri.getNodeValue());
+ return new XMLSignatureInput(x);
+ }
+
+ @Override
+ public boolean engineCanResolve(Attr uri, String baseURI) {
+ if (uri == null) {
+ return false;
+ }
+
+ String uriNodeValue = uri.getNodeValue();
+
+ if (uriNodeValue.equals("") || (uriNodeValue.charAt(0)=='#') ||
+ uriNodeValue.startsWith("http:")) {
+ return false;
+ }
+
+ if (uriNodeValue.startsWith("cid:") || baseURI.startsWith("cid:")) {
+ return true;
+ }
+
+ return false;
+ }
+
+}
34 src/main/java/com/barostudio/nts/ext/TransformAttachementContentSignature.java
@@ -0,0 +1,34 @@
+package com.barostudio.nts.ext;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xml.security.c14n.CanonicalizationException;
+import org.apache.xml.security.c14n.InvalidCanonicalizerException;
+import org.apache.xml.security.signature.XMLSignatureInput;
+import org.apache.xml.security.transforms.Transform;
+import org.apache.xml.security.transforms.TransformSpi;
+import org.apache.xml.security.transforms.TransformationException;
+import org.xml.sax.SAXException;
+
+public class TransformAttachementContentSignature extends TransformSpi {
+
+ public static String implementedTransformURI =
+ "http://docs.oasis-open.org/wss/oasis-wss-SwAProfile-1.1#Attachment-Content-Signature-Transform";
+
+ @Override
+ protected String engineGetURI() {
+ return implementedTransformURI;
+ }
+
+ @Override
+ protected XMLSignatureInput enginePerformTransform(XMLSignatureInput input,
+ OutputStream os, Transform transformObject) throws IOException,
+ CanonicalizationException, InvalidCanonicalizerException,
+ TransformationException, ParserConfigurationException, SAXException {
+ return new XMLSignatureInput(input.getBytes());
+ }
+
+}
BIN  src/main/resources/KmCert.der
Binary file not shown
96 src/main/resources/unsigned.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TaxInvoice xmlns="urn:kr:or:kec:standard:Tax:ReusableAggregateBusinessInformationEntitySchemaModule:1:0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:kr:or:kec:standard:Tax:ReusableAggregateBusinessInformationEntitySchemaModule:1:0 http://www.kec.or.kr/standard/Tax/TaxInvoiceSchemaModule_1.0.xsd">
+ <ExchangedDocument>
+ <ID>TESTSEND-090900028</ID>
+ <IssueDateTime>20090914220351</IssueDateTime>
+ <ReferencedDocument>
+ <ID>TESTSEND-090900028</ID>
+ </ReferencedDocument>
+ </ExchangedDocument>
+ <TaxInvoiceDocument>
+ <IssueID>200909143900502610018801</IssueID>
+ <TypeCode>0101</TypeCode>
+ <IssueDateTime>20090914</IssueDateTime>
+ <PurposeCode>02</PurposeCode>
+ </TaxInvoiceDocument>
+ <TaxInvoiceTradeSettlement>
+ <InvoicerParty>
+ <ID>2048631263</ID>
+ <TypeCode>통신업,도소매,부동산,사업서비스</TypeCode>
+ <NameText>(주)샘플사업자</NameText>
+ <ClassificationCode>부가통신업,컴퓨터 및 주변기기</ClassificationCode>
+ <SpecifiedOrganization>
+ <TaxRegistrationID>1111</TaxRegistrationID>
+ </SpecifiedOrganization>
+ <SpecifiedPerson>
+ <NameText>홍길동</NameText>
+ </SpecifiedPerson>
+ <DefinedContact>
+ <DepartmentNameText>전자인증TF</DepartmentNameText>
+ <PersonNameText>NTSTEST</PersonNameText>
+ <TelephoneCommunication>025387227</TelephoneCommunication>
+ <URICommunication>cmy1203@klnet.co.kr</URICommunication>
+ </DefinedContact>
+ <SpecifiedAddress>
+ <LineOneText>서울 강남구 역삼동</LineOneText>
+ </SpecifiedAddress>
+ </InvoicerParty>
+ <InvoiceeParty>
+ <ID>6028131841</ID>
+ <TypeCode>운송,서비스</TypeCode>
+ <NameText>상하차업체</NameText>
+ <ClassificationCode>화물자동차운송및 운송주선</ClassificationCode>
+ <SpecifiedOrganization>
+ <BusinessTypeCode>01</BusinessTypeCode>
+ </SpecifiedOrganization>
+ <SpecifiedPerson>
+ <NameText>홍길동</NameText>
+ </SpecifiedPerson>
+ <PrimaryDefinedContact>
+ <DepartmentNameText>관리부</DepartmentNameText>
+ <PersonNameText>김경규</PersonNameText>
+ <TelephoneCommunication>0514627784</TelephoneCommunication>
+ <URICommunication>giminlu@freechal.com</URICommunication>
+ </PrimaryDefinedContact>
+ <SpecifiedAddress>
+ <LineOneText>서울 강남</LineOneText>
+ </SpecifiedAddress>
+ </InvoiceeParty>
+ <SpecifiedPaymentMeans>
+ <TypeCode>10</TypeCode>
+ <PaidAmount>110000000</PaidAmount>
+ </SpecifiedPaymentMeans>
+ <SpecifiedPaymentMeans>
+ <TypeCode>20</TypeCode>
+ <PaidAmount>0</PaidAmount>
+ </SpecifiedPaymentMeans>
+ <SpecifiedPaymentMeans>
+ <TypeCode>30</TypeCode>
+ <PaidAmount>0</PaidAmount>
+ </SpecifiedPaymentMeans>
+ <SpecifiedPaymentMeans>
+ <TypeCode>40</TypeCode>
+ <PaidAmount>0</PaidAmount>
+ </SpecifiedPaymentMeans>
+ <SpecifiedMonetarySummation>
+ <ChargeTotalAmount>100000000</ChargeTotalAmount>
+ <TaxTotalAmount>10000000</TaxTotalAmount>
+ <GrandTotalAmount>110000000</GrandTotalAmount>
+ </SpecifiedMonetarySummation>
+ </TaxInvoiceTradeSettlement>
+ <TaxInvoiceTradeLineItem>
+ <SequenceNumeric>1</SequenceNumeric>
+ <DescriptionText></DescriptionText>
+ <InvoiceAmount>100000000</InvoiceAmount>
+ <ChargeableUnitQuantity>1</ChargeableUnitQuantity>
+ <InformationText></InformationText>
+ <NameText>한석봉</NameText>
+ <PurchaseExpiryDateTime>20090914</PurchaseExpiryDateTime>
+ <TotalTax>
+ <CalculatedAmount>10000000</CalculatedAmount>
+ </TotalTax>
+ <UnitPrice>
+ <UnitAmount>100000000</UnitAmount>
+ </UnitPrice>
+ </TaxInvoiceTradeLineItem>
+</TaxInvoice>
0  target/.gitkeep
No changes.
Please sign in to comment.
Something went wrong with that request. Please try again.