/** * Create Idemix Identity from a Serialized Identity * * @param proto */ public IdemixIdentity(SerializedIdentity proto) { if (proto == null) { throw new ArgumentException("Input must not be null"); } mspId = proto.Mspid; try { logger.Trace("Fetching Idemix Proto"); SerializedIdemixIdentity idemixProto = SerializedIdemixIdentity.Parser.ParseFrom(proto.IdBytes); if (idemixProto == null) { throw new ArgumentException("The identity does not contain a serialized idemix identity"); } logger.Trace("Deserializing Nym and attribute values"); pseudonym = new ECP(BIG.FromBytes(idemixProto.NymX.ToByteArray()), BIG.FromBytes(idemixProto.NymY.ToByteArray())); OrganizationUnit ou = OrganizationUnit.Parser.ParseFrom(idemixProto.Ou); MSPRole role = MSPRole.Parser.ParseFrom(idemixProto.Role); Ou = ou.OrganizationalUnitIdentifier; RoleMask = role.Role.ToIdemixRole(); ipkHash = ou.CertifiersIdentifier.ToByteArray(); logger.Trace("Deserializing Proof"); associationProof = new IdemixSignature(Signature.Parser.ParseFrom(idemixProto.Proof.ToByteArray())); } catch (InvalidProtocolBufferException e) { throw new CryptoException("Cannot deserialize MSP ID", e); } }
/** * Create Idemix Identity from the following inputs: * * @param mspId is MSP ID sting * @param nym is Identity Mixer Pseudonym * @param ou is OU attribute * @param roleMask is a bitmask that represent all the roles attached to this identity * @param proof is Proof */ public IdemixIdentity(string mspId, IdemixIssuerPublicKey ipk, ECP nym, string ou, IdemixRoles roleMask, IdemixSignature proof) { if (mspId == null) { throw new ArgumentException("MSP ID must not be null"); } if (string.IsNullOrEmpty(mspId)) { throw new ArgumentException("MSP ID must not be empty"); } if (ipk == null) { throw new ArgumentException("Issuer Public Key must not be empty"); } if (nym == null) { throw new ArgumentException("Identity Mixer Pseudonym (nym) must not be null"); } if (ou == null) { throw new ArgumentException("OU attribute must not be null"); } if (string.IsNullOrEmpty(ou)) { throw new ArgumentException("OU attribute must not be empty"); } if (proof == null) { throw new ArgumentException("Proof must not be null"); } this.mspId = mspId; ipkHash = ipk.Hash; pseudonym = nym; Ou = ou; RoleMask = roleMask; associationProof = proof; }
/** * Create new Idemix Signing Identity with a fresh pseudonym * * @param ipk issuer public key * @param revocationPk the issuer's long term revocation public key * @param mspId MSP identifier * @param sk user's secret * @param cred idemix credential * @param cri the credential revocation information * @param ou is OU attribute * @param role is role attribute * @throws CryptoException * @throws InvalidArgumentException */ public IdemixSigningIdentity(IdemixIssuerPublicKey ipk, KeyPair revocationPk, string mspId, BIG sk, IdemixCredential cred, CredentialRevocationInformation cri, string ou, IdemixRoles role) { // input checks if (ipk == null) { throw new ArgumentException("Issuer Public Key (IPK) must not be null"); } if (revocationPk == null) { throw new ArgumentException("Revocation PK must not be null"); } if (mspId == null) { throw new ArgumentException("MSP ID must not be null"); } if (string.IsNullOrEmpty(mspId)) { throw new ArgumentException("MSP ID must not be empty"); } if (ou == null) { throw new ArgumentException("OU must not be null"); } if (string.IsNullOrEmpty(ou)) { throw new ArgumentException("OU must not be empty"); } if (sk == null) { throw new ArgumentException("SK must not be null"); } if (cred == null) { throw new ArgumentException("Credential must not be null"); } if (cri == null) { throw new ArgumentException("Credential revocation information must not be null"); } logger.Trace($"Verifying public key with hash: [{BitConverter.ToString(ipk.Hash).Replace("-", "")}] \nAttributes: [{string.Join(",", ipk.AttributeNames)}]"); if (!ipk.Check()) { CryptoException e = new CryptoException("Issuer public key is not valid"); logger.Error("", e); throw e; } this.ipk = ipk; this.sk = sk; this.cri = cri; logger.Trace("Verifying the credential"); // cryptographically verify credential // (check if the issuer's signature is valid) if (!cred.Verify(sk, ipk)) { CryptoException e = new CryptoException("Credential is not cryptographically valid"); logger.Error("", e); throw e; } logger.Trace("Checking attributes"); // attribute checks // 4 attributes are expected: // - organization unit (disclosed) // - role: admin or member (disclosed) // - enrollment id (hidden, for future auditing feature and authorization with CA) // - revocation handle (hidden, for future revocation support) if (cred.Attrs.Length != 4) { throw new CryptoException($"Error: There are {cred.Attrs.Length} attributes and the expected are 4"); } byte[] ouBytes = cred.Attrs[0]; byte[] roleBytes = cred.Attrs[1]; byte[] eIdBytes = cred.Attrs[2]; byte[] rHBytes = cred.Attrs[3]; BIG[] attributes = new BIG[4]; attributes[0] = BIG.FromBytes(ouBytes); attributes[1] = BIG.FromBytes(roleBytes); attributes[2] = BIG.FromBytes(eIdBytes); attributes[3] = BIG.FromBytes(rHBytes); // check that the OU string matches the credential's attribute value if (!ou.ToBytes().HashModOrder().ToBytes().SequenceEqual(ouBytes)) { throw new ArgumentException("the OU string does not match the credential"); } // check that the role matches the credential's attribute value if (!new BIG((int)role).ToBytes().SequenceEqual(roleBytes)) { throw new ArgumentException("the role does not match the credential"); } logger.Trace("Generating fresh pseudonym and proof"); // generate a fresh pseudonym Pseudonym = new IdemixPseudonym(this.sk, this.ipk); // generate a fresh proof of possession of a credential // with respect to a freshly generated pseudonym Proof = new IdemixSignature(cred, this.sk, Pseudonym, this.ipk, disclosedFlags, msgEmpty, rhIndex, cri); logger.Trace("Verifying the proof"); // verify the proof if (!Proof.Verify(disclosedFlags, this.ipk, msgEmpty, attributes, rhIndex, revocationPk, (int)cri.Epoch)) { throw new CryptoException("Generated proof of identity is not valid"); } logger.Trace("Generating the Identity Object"); // generate a fresh identity with new pseudonym idemixIdentity = new IdemixIdentity(mspId, this.ipk, Pseudonym.Nym, ou, role, Proof); logger.Trace(idemixIdentity.ToString()); }
private void Test() { RAND rng = IdemixUtils.GetRand(); // WeakBB test // Random message to sign BIG wbbMessage = rng.RandModOrder(); // Sign the message with keypair secret key ECP wbbSignature = WeakBB.WeakBBSign(setup.wbbKeyPair.Sk, wbbMessage); // Check the signature with valid PK and valid message Assert.IsTrue(WeakBB.weakBBVerify(setup.wbbKeyPair.Pk, wbbSignature, wbbMessage)); // Try to check a random message Assert.IsFalse(WeakBB.weakBBVerify(setup.wbbKeyPair.Pk, wbbSignature, rng.RandModOrder())); // user completes the idemixCredential and checks validity Assert.IsTrue(setup.idemixCredential.Verify(setup.sk, setup.key.Ipk)); // Test serialization of IdemixidemixCredential Assert.IsTrue(new IdemixCredential(setup.idemixCredential.ToProto()).Verify(setup.sk, setup.key.Ipk)); // Create CRI that contains no revocation mechanism int epoch = 0; BIG[] rhIndex = { new BIG(0) }; CredentialRevocationInformation cri = RevocationAuthority.CreateCRI(setup.revocationKeyPair, rhIndex, epoch, RevocationAlgorithm.ALG_NO_REVOCATION); // Create a new unlinkable pseudonym IdemixPseudonym pseudonym = new IdemixPseudonym(setup.sk, setup.key.Ipk); //tcert // Test signing no disclosure bool[] disclosure = { false, false, false, false, false }; byte[] msg = { 1, 2, 3, 4, 5 }; IdemixSignature signature = new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, disclosure, msg, 0, cri); Assert.IsNotNull(signature); // Test bad disclosure: Disclosure > number of attributes || Disclosure < number of attributes bool[] badDisclosure = { false, true }; bool[] badDisclosure2 = { true, true, true, true, true, true, true }; try { new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, badDisclosure, msg, 0, cri); new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, badDisclosure2, msg, 0, cri); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { //ignored /* Do nothing, the expected behaviour is to catch this exception.*/ } // check that the signature is valid Assert.IsTrue(signature.Verify(disclosure, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Test serialization of IdemixSignature Assert.IsTrue(new IdemixSignature(signature.ToProto()).Verify(disclosure, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Test signing selective disclosure bool[] disclosure2 = { false, true, true, true, false }; signature = new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, disclosure2, msg, 0, cri); Assert.IsNotNull(signature); // check that the signature is valid Assert.IsTrue(signature.Verify(disclosure2, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Test signature verification with different disclosure Assert.IsFalse(signature.Verify(disclosure, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // test signature verification with different issuer public key Assert.IsFalse(signature.Verify(disclosure2, new IdemixIssuerKey(new [] { "Attr1, Attr2, Attr3, Attr4, Attr5" }).Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // test signature verification with different message byte[] msg2 = { 1, 1, 1 }; Assert.IsFalse(signature.Verify(disclosure2, setup.key.Ipk, msg2, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Sign a message with respect to a pseudonym IdemixPseudonymSignature nymsig = new IdemixPseudonymSignature(setup.sk, pseudonym, setup.key.Ipk, msg); // check that the pseudonym signature is valid Assert.IsTrue(nymsig.Verify(pseudonym.Nym, setup.key.Ipk, msg)); // Test serialization of IdemixPseudonymSignature Assert.IsTrue(new IdemixPseudonymSignature(nymsig.ToProto()).Verify(pseudonym.Nym, setup.key.Ipk, msg)); }
public static void Setup(TestContext context) { // Parse crypto material from files IdemixMSPSignerConfig signerConfig = null; try { signerConfig = ReadIdemixMSPConfig(Path.Combine(TEST_PATH, MSP1OU1, USER_PATH).Locate(), SIGNER_CONFIG); } catch (System.Exception e) { Assert.Fail("Unexpected exception while reading signerconfig: " + e.Message); } Assert.IsNotNull(signerConfig); try { revocationPk = ReadIdemixRevocationPublicKey(Path.Combine(TEST_PATH, MSP1OU1, VERIFIER_PATH).Locate(), REVOCATION_PUBLIC_KEY); } catch (System.Exception e) { Assert.Fail("Unexpected exception while reading revocation public key: " + e.Message); } Assert.IsNotNull(revocationPk); IssuerPublicKey ipkProto = null; try { ipkProto = ReadIdemixIssuerPublicKey(Path.Combine(TEST_PATH, MSP1OU1, VERIFIER_PATH).Locate(), IPK_CONFIG); } catch (IOException e1) { Assert.Fail("Unexpected exception while reading revocation public key" + e1.Message); } ipk = new IdemixIssuerPublicKey(ipkProto); Assert.IsTrue(ipk.Check()); sk = BIG.FromBytes(signerConfig.Sk.ToByteArray()); Credential credProto = null; try { credProto = Credential.Parser.ParseFrom(signerConfig.Cred); } catch (InvalidProtocolBufferException) { Assert.Fail("Could not parse a credential"); } Assert.IsNotNull(credProto); cred = new IdemixCredential(credProto); try { cri = CredentialRevocationInformation.Parser.ParseFrom(signerConfig.CredentialRevocationInformation); } catch (InvalidProtocolBufferException e) { Assert.Fail("failed to extract cri from signer config: " + e.Message); } Assert.IsNotNull(cri); try { signingIdentity = new IdemixSigningIdentity(ipk, revocationPk, MSP1OU1, sk, cred, cri, OU1, IdemixRoles.MEMBER); } catch (System.Exception e) when(e is CryptoException || e is ArgumentException) { Assert.Fail("Could not create Idemix Signing Identity" + e.Message); } Assert.IsNotNull(signingIdentity); nym = signingIdentity.Pseudonym; nymPublic = nym.Nym; proof = signingIdentity.Proof; }