-
-
Save muromec/cfe8da5135084bea50aff5670bde110f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collectionsusing System; | |
using System.Collections.Generic; | |
using System.Collections; | |
using System.Text; | |
using System.IO; | |
using System.Linq; | |
using Org.BouncyCastle.Security; | |
using Org.BouncyCastle.Utilities.Encoders; | |
using Org.BouncyCastle.Math; | |
using Org.BouncyCastle.Math.EC; | |
using Org.BouncyCastle.Crypto; | |
using Org.BouncyCastle.Crypto.Parameters; | |
using Org.BouncyCastle.Crypto.Signers; | |
using Org.BouncyCastle.Crypto.Digests; | |
using Org.BouncyCastle.Asn1; | |
using Org.BouncyCastle.Asn1.X509; | |
using Org.BouncyCastle.Asn1.Cms; | |
using Org.BouncyCastle.Asn1.Pkcs; | |
using Org.BouncyCastle.Asn1.UA; | |
using Org.BouncyCastle.Asn1.Ess; | |
using Org.BouncyCastle.Utilities.Test; | |
using Org.BouncyCastle.Cms; | |
using Org.BouncyCastle.X509; | |
public class K { | |
static readonly byte[] sBoxParam = { | |
0xA,0x9,0xD,0x6,0xE,0xB,0x4,0x5,0xF,0x1,0x3,0xC,0x7,0x0,0x8,0x2, // K1 | |
0x8,0x0,0xC,0x4,0x9,0x6,0x7,0xB,0x2,0x3,0x1,0xF,0x5,0xE,0xA,0xD, // K2 | |
0xF,0x6,0x5,0x8,0xE,0xB,0xA,0x4,0xC,0x0,0x3,0x7,0x2,0x9,0x1,0xD, // K3 | |
0x3,0x8,0xD,0x9,0x6,0xB,0xF,0x0,0x2,0x5,0xC,0xA,0x4,0xE,0x1,0x7, // K4 | |
0xF,0x8,0xE,0x9,0x7,0x2,0x0,0xD,0xC,0x6,0x1,0x5,0xB,0x4,0x3,0xA, // K5 | |
0x2,0x8,0x9,0x7,0x5,0xF,0x0,0xB,0xC,0x1,0xD,0xE,0xA,0x3,0x6,0x4, // K6 | |
0x3,0x8,0xB,0x5,0x6,0x4,0xE,0xA,0x2,0xC,0x1,0x7,0x9,0xF,0xD,0x0, // K7 | |
0x1,0x2,0x3,0xE,0x6,0xD,0xB,0x8,0xF,0xA,0xC,0x5,0x7,0x9,0x0,0x4, // K8 | |
}; | |
public static byte[] GetHash(byte[] data) { | |
byte[] hash = new byte[32]; | |
Gost3411Digest digest = new Gost3411Digest(sBoxParam); | |
digest.BlockUpdate(data, 0, data.Length); | |
digest.DoFinal(hash, 0); | |
return hash; | |
} | |
public static byte[] GetSignature(ICipherParameters privKey, byte[] data, bool isLE) { | |
Dstu4145Signer dstuSigner = new Dstu4145Signer(); | |
dstuSigner.Init(true, privKey); | |
BigInteger[] rs = dstuSigner.GenerateSignature(GetHash(data)); | |
byte[] r = rs[0].ToByteArray(); | |
byte[] s = rs[1].ToByteArray(); | |
if (isLE) { | |
reverseBytes(r); | |
reverseBytes(s); | |
} | |
return r.Concat(s).ToArray(); | |
} | |
private static byte[] ToDER(Asn1Encodable inObj) { | |
MemoryStream bOut = new MemoryStream(); | |
DerOutputStream aOut = new DerOutputStream(bOut); | |
aOut.WriteObject(inObj); | |
return bOut.ToArray(); | |
} | |
private static byte[] FileToByteArray(string filename) { | |
byte[] buf = null; | |
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read); | |
BinaryReader br = new BinaryReader(fs); | |
long numBytes = new FileInfo(filename).Length; | |
buf = br.ReadBytes((int)numBytes); | |
return buf; | |
} | |
private static void reverseBytes(byte[] bytes) { | |
byte tmp; | |
for (int i = 0; i < bytes.Length / 2; i++) { | |
tmp = bytes[i]; | |
bytes[i] = bytes[bytes.Length - 1 - i]; | |
bytes[bytes.Length - 1 - i] = tmp; | |
} | |
} | |
public static void Main(String[] args) { | |
Asn1Sequence keyInfo = Asn1Sequence.GetInstance( | |
new Asn1InputStream( | |
FileToByteArray(args[0]) | |
).ReadObject() | |
); | |
IEnumerator e = keyInfo.GetEnumerator(); | |
e.MoveNext(); | |
BigInteger version = ((DerInteger)e.Current).Value; | |
e.MoveNext(); | |
AlgorithmIdentifier algId = AlgorithmIdentifier.GetInstance(e.Current); | |
if (!algId.Algorithm.Equals(UAObjectIdentifiers.dstu4145le)) { | |
return; | |
} | |
bool isLE = algId.Algorithm.Equals(UAObjectIdentifiers.dstu4145le); | |
e.MoveNext(); | |
Asn1OctetString asnD = Asn1OctetString.GetInstance(e.Current); | |
byte[] secretD = asnD.GetOctets(); | |
if (isLE) { | |
reverseBytes(secretD); | |
} | |
BigInteger d = new BigInteger(secretD); | |
DSTU4145Params dstuParams = DSTU4145Params.GetInstance(algId.Parameters); | |
ECDomainParameters ecDomain; | |
if (dstuParams.isNamedCurve()) { | |
DerObjectIdentifier curveOid = dstuParams.getNamedCurve(); | |
ecDomain = DSTU4145NamedCurves.getByOID(curveOid); | |
} | |
else { | |
DSTU4145ECBinary binary = dstuParams.getECBinary(); | |
byte[] b_bytes = binary.getB(); | |
if (isLE) { | |
reverseBytes(b_bytes); | |
} | |
DSTU4145BinaryField field = binary.getField(); | |
ECCurve curve = new F2mCurve(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes)); | |
byte[] g_bytes = binary.getG(); | |
if (isLE) { | |
reverseBytes(g_bytes); | |
} | |
ecDomain = new ECDomainParameters(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN()); | |
} | |
ICipherParameters privKey = new ECPrivateKeyParameters(d, ecDomain); | |
byte[] data = Encoding.ASCII.GetBytes("Hello World!"); | |
byte[] hash = GetHash(data); | |
CmsProcessable content = new CmsProcessableByteArray(data); | |
Asn1EncodableVector digestAlgs = new Asn1EncodableVector(); | |
Asn1EncodableVector signerInfos = new Asn1EncodableVector(); | |
Asn1EncodableVector certificates = new Asn1EncodableVector(); | |
Asn1EncodableVector signedAttrsV = new Asn1EncodableVector(); | |
Asn1Set certrevlist = null; | |
Asn1Set signedAttr = null; | |
Asn1Set unsignedAttr = null; | |
digestAlgs.Add(new AlgorithmIdentifier(UAObjectIdentifiers.gost34311)); | |
byte[] certBytes = FileToByteArray(args[1]); | |
X509CertificateStructure certAsn = X509CertificateStructure.GetInstance( | |
new Asn1InputStream(certBytes).ReadObject() | |
); | |
X509Certificate cert = new X509Certificate(certAsn); | |
certificates.Add(certAsn); | |
IssuerSerial issuerSerial = new IssuerSerial( | |
new GeneralNames(new GeneralName(cert.IssuerDN)), | |
new DerInteger(cert.SerialNumber) | |
); | |
EssCertIDv2 certidv2 = new EssCertIDv2( | |
new AlgorithmIdentifier(UAObjectIdentifiers.gost34311), | |
GetHash(certBytes), | |
issuerSerial | |
); | |
signedAttrsV.Add(new Org.BouncyCastle.Asn1.Cms.Attribute( | |
PkcsObjectIdentifiers.IdAASigningCertificateV2, | |
new DerSet(new DerSequence(new DerSequence(certidv2))) | |
)); | |
signedAttrsV.Add(new Org.BouncyCastle.Asn1.Cms.Attribute( | |
CmsAttributes.ContentType, | |
new DerSet(CmsObjectIdentifiers.Data) | |
)); | |
signedAttrsV.Add(new Org.BouncyCastle.Asn1.Cms.Attribute( | |
CmsAttributes.MessageDigest, | |
new DerSet(new DerOctetString(hash)) | |
)); | |
signedAttrsV.Add(new Org.BouncyCastle.Asn1.Cms.Attribute( | |
PkcsObjectIdentifiers.Pkcs9AtSigningTime, | |
new DerSet(new DerUtcTime(new DateTime())) | |
)); | |
signedAttr = new DerSet(signedAttrsV); | |
byte[] signatureRS = GetSignature(privKey, ToDER(signedAttr), isLE); | |
SignerIdentifier sid = new SignerIdentifier(CmsUtilities.GetIssuerAndSerialNumber(cert)); | |
signerInfos.Add( | |
new Org.BouncyCastle.Asn1.Cms.SignerInfo( | |
sid, | |
new AlgorithmIdentifier(UAObjectIdentifiers.gost34311), | |
signedAttr, | |
new AlgorithmIdentifier(UAObjectIdentifiers.dstu4145le), | |
new DerOctetString(signatureRS), | |
unsignedAttr | |
) | |
); | |
Asn1OctetString octs = new DerOctetString(data); | |
Org.BouncyCastle.Asn1.Cms.ContentInfo encInfo = new Org.BouncyCastle.Asn1.Cms.ContentInfo(CmsObjectIdentifiers.Data, octs); | |
Org.BouncyCastle.Asn1.Cms.SignedData sd = new Org.BouncyCastle.Asn1.Cms.SignedData( | |
new DerSet(digestAlgs), | |
encInfo, | |
new DerSet(certificates), | |
certrevlist, | |
new DerSet(signerInfos) | |
); | |
Org.BouncyCastle.Asn1.Cms.ContentInfo contentInfo = new Org.BouncyCastle.Asn1.Cms.ContentInfo(CmsObjectIdentifiers.SignedData, sd); | |
CmsSignedData signedCMS = new CmsSignedData(content, contentInfo); | |
byte[] coded = ToDER(signedCMS.ContentInfo); | |
using (BinaryWriter writer = new BinaryWriter( | |
File.Open(args[2], FileMode.Create) | |
)) { | |
writer.Write(coded); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment