<p>After the <a href="https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030" rel="nofollow noreferrer">CIP-0030</a> update you won't get the <code>publicKey</code> in the protected headers, but rather in the response object from <code>signData</code> directly, so the above answer won't work anymore.</p>
<p>Here is the example of the verification after the update: <a href="https://github.com/MartinOndejka/cip-0008-verification" rel="nofollow noreferrer">https://github.com/MartinOndejka/cip-0008-verification</a></p>

CC BY-SA 4.0
2022-11-03T21:42:34.550Z
2022-11-03T21:42:34.550Z
Martin Ondejka
<p>First part of the solution can be found here:</p>
<p><a href="https://github.com/bloxbean/cardano-client-examples/blob/cip008/src/main/java/com/bloxbean/cardano/client/examples/cip8/CIP8CBORParser.java" rel="nofollow noreferrer">https://github.com/bloxbean/cardano-client-examples/blob/cip008/src/main/java/com/bloxbean/cardano/client/examples/cip8/CIP8CBORParser.java</a></p>
<p>Code pasted here to keep track</p>
<pre><code>package com.bloxbean.cardano.client.examples.cip8;

import co.nstant.in.cbor.CborDecoder;
import co.nstant.in.cbor.model.*;
import com.bloxbean.cardano.client.crypto.CryptoException;
import com.bloxbean.cardano.client.transaction.util.CborSerializationUtil;
import com.bloxbean.cardano.client.util.HexUtil;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;

import java.security.MessageDigest;
import java.security.Signature;
import java.util.List;

public class CIP8CBORParser {
    private static final EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);

    public void parse() throws Exception {
        //Payload = &quot;hello&quot;
        String coseSignMsgInHex = &quot;845869a30127045820674d11e432450118d70ea78673d5e31d5cc1aec63de0ff6284784876544be3406761646472657373583901d2eb831c6cad4aba700eb35f86966fbeff19d077954430e32ce65e8da79a3abe84f4ce817fad066acc1435be2ffc6bd7dce2ec1cc6cca6cba166686173686564f44568656c6c6f5840a3b5acd99df5f3b5e4449c5a116078e9c0fcfc126a4d4e2f6a9565f40b0c77474cafd89845e768fae3f6eec0df4575fcfe7094672c8c02169d744b415c617609&quot;;

        //CBOR parsing starts here ###################
        List&lt;DataItem&gt; dataItemList  = CborDecoder.decode(HexUtil.decodeHexString(coseSignMsgInHex));

        List&lt;DataItem&gt; topArray = ((Array) dataItemList.get(0)).getDataItems();
        ByteString protectedHeaderBs = (ByteString) topArray.get(0);
        Map unprotectedMap = (Map) topArray.get(1);
        ByteString messageToSignBS = (ByteString) topArray.get(2);
        ByteString signatureArrayBS = (ByteString) topArray.get(3);

        byte[] message = messageToSignBS.getBytes();
        byte[] signature = signatureArrayBS.getBytes();

        System.out.println(new String(message));

        //parse protected header map bytestring
        List&lt;DataItem&gt; protectedHeaderMapDIList = CborDecoder.decode(protectedHeaderBs.getBytes());
        Map protectedHeaderMap = (Map) protectedHeaderMapDIList.get(0);

        ByteString publicKeyBS = (ByteString) protectedHeaderMap.get(new UnsignedInteger(4));
        byte[] publicKeyBytes = publicKeyBS.getBytes();

        ByteString addressBS = (ByteString)protectedHeaderMap.get(new UnicodeString(&quot;address&quot;));
        System.out.println(&quot;Address &gt;&gt; &quot; + HexUtil.encodeHexString(addressBS.getBytes()));
        //CBOR parsing ends her ###################

        //Create SignatureStructure. This is passed as message during signature verification
        Array sigStructArray = new Array();
        sigStructArray.add(new UnicodeString(&quot;Signature1&quot;));
        sigStructArray.add(protectedHeaderBs);
        sigStructArray.add(new ByteString(new byte[0]));
        sigStructArray.add(messageToSignBS);

        byte[] messageToVerify = CborSerializationUtil.serialize(sigStructArray); //serialize
        //End SignatureStructure

        boolean verified = verify(messageToVerify, signature, publicKeyBytes);
        System.out.println(&quot;Verification status &gt;&gt; &quot; + verified);
    }

    public boolean verify(byte[] message, byte[] signatureBytes, byte[] publicKeyBytes) {

        try{
            net.i2p.crypto.eddsa.EdDSAPublicKey publicKey = new net.i2p.crypto.eddsa.EdDSAPublicKey(new EdDSAPublicKeySpec(publicKeyBytes, spec));
            Signature signature = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
            signature.initVerify(publicKey);
            signature.setParameter(EdDSAEngine.ONE_SHOT_MODE);
            signature.update(message);
            return signature.verify(signatureBytes);
        }catch(Exception e){
            throw new CryptoException(&quot;Extended signing error&quot;, e);
        }
    }

    public static void main(String[] args) throws Exception {
        new CIP8CBORParser().parse();
    }
}
</code></pre>
<p>Kudos to <a href="https://twitter.com/satran004" rel="nofollow noreferrer">@Satya</a></p>
<p>Second part missing is the adderss verificaiton/validation.</p>
<p>Will add as soon as it's done.</p>

CC BY-SA 4.0
2022-04-04T13:53:54.567Z
2022-04-04T13:53:54.567Z
Giovanni G
<p>I'm trying to implement what's discussed in this topic: <a href="https://cardano.stackexchange.com/questions/2498/how-to-verify-data-signed-with-nami-wallet-in-a-node-backend">How to verify data signed with nami wallet in a node backend?</a> but in Java.</p>
<p>Obviously I don't have the js/rust lib I can play with, so I have to implement/integrate all the bits myself.</p>
<p>While I've successfully implemented the code to use the Ed25519 standard, and in this repo there is the code and a few examples <a href="https://github.com/speedwing/blockchain-auth-mech-dev/blob/master/lib/src/main/java/blockchain/auth/mech/signing/wallet/SigningService.java" rel="nofollow noreferrer">github</a> I don't seem to be able to verify the data returned by the signData method of the wallet (that I assume uses the same standard).</p>
<p>Now it's my understading that the COSE object contains all that I need to <em>at least</em> verify the payload has been signed with the public key returned with COSE object itself. Looking at the sample in the post above, and using the <a href="https://cbor.me/" rel="nofollow noreferrer">https://cbor.me/</a> website, I guess that:</p>
<ol>
<li><code>674D11E432450118D70EA78673D5E31D5CC1AEC63DE0FF6284784876544BE340</code> is the HEX of the signed message</li>
<li><code>68656C6C6F</code> is the HEX of the message to sign</li>
<li><code>01D2EB831C6CAD4ABA700EB35F86966FBEFF19D077954430E32CE65E8DA79A3ABE84F4CE817FAD066ACC1435BE2FFC6BD7DCE2EC1CC6CCA6CB</code> is the HEX of the Base Address of the wallet</li>
<li><code>A3B5ACD99DF5F3B5E4449C5A116078E9C0FCFC126A4D4E2F6A9565F40B0C77474CAFD89845E768FAE3F6EEC0DF4575FCFE7094672C8C02169D744B415C617609</code> is the HEX of the Public Key of the wallet.</li>
</ol>
<p>Now, if I used the public key at (4) along with signed (1) and unsigned (2), and I test with the code (taht I know that works!) I wrong for the verification, it doesn't pass. So I guess one of the assumption i wrong.</p>
<p>I'm sure that (2) is the hex of the message to sign, so now either (1) is not the signed message or (4) is not the public key. Or they are in a different format</p>
<p>In java the code I'm running looks like the following</p>
<pre><code>var msg = &quot;hello&quot;.getBytes(StandardCharsets.UTF_8);
var publicKey = new Ed25519PublicKeyParameters(Hex.decode(&quot;A3B5ACD99DF5F3B5E4449C5A116078E9C0FCFC126A4D4E2F6A9565F40B0C77474CAFD89845E768FAE3F6EEC0DF4575FCFE7094672C8C02169D744B415C617609&quot;), 0);
var verifier = new Ed25519Signer();
verifier.init(false, publicKey);
verifier.update(msg, 0, msg.length);
var outcome = verifier.verifySignature(Hex.decode(&quot;674D11E432450118D70EA78673D5E31D5CC1AEC63DE0FF6284784876544BE340&quot;));
System.out.println(&quot;Outcome: &quot; + outcome);
</code></pre>
<p>Any help would be greatly appreciated</p>

<wallet>
Implementing CIP-008 (signData function) in Java
# Implementing CIP-008 (signData function) in Java

(Asked by: username_0 on 2022-04-02)

I'm trying to implement what's discussed in this topic: How to verify data signed with nami wallet in a node backend? but in Java.
Obviously I don't have the js/rust lib I can play with, so I have to implement/integrate all the bits myself.
While I've successfully implemented the code to use the Ed25519 standard, and in this repo there is the code and a few examples github I don't seem to be able to verify the data returned by the signData method of the wallet (that I assume uses the same standard).
Now it's my understading that the COSE object contains all that I need to at least verify the payload has been signed with the public key returned with COSE object itself. Looking at the sample in the post above, and using the https://cbor.me/ website, I guess that:

674D11E432450118D70EA78673D5E31D5CC1AEC63DE0FF6284784876544BE340 is the HEX of the signed message
68656C6C6F is the HEX of the message to sign
01D2EB831C6CAD4ABA700EB35F86966FBEFF19D077954430E32CE65E8DA79A3ABE84F4CE817FAD066ACC1435BE2FFC6BD7DCE2EC1CC6CCA6CB is the HEX of the Base Address of the wallet
A3B5ACD99DF5F3B5E4449C5A116078E9C0FCFC126A4D4E2F6A9565F40B0C77474CAFD89845E768FAE3F6EEC0DF4575FCFE7094672C8C02169D744B415C617609 is the HEX of the Public Key of the wallet.

Now, if I used the public key at (4) along with signed (1) and unsigned (2), and I test with the code (taht I know that works!) I wrong for the verification, it doesn't pass. So I guess one of the assumption i wrong.
I'm sure that (2) is the hex of the message to sign, so now either (1) is not the signed message or (4) is not the public key. Or they are in a different format
In java the code I'm running looks like the following
var msg = "hello".getBytes(StandardCharsets.UTF_8);
var publicKey = new Ed25519PublicKeyParameters(Hex.decode("A3B5ACD99DF5F3B5E4449C5A116078E9C0FCFC126A4D4E2F6A9565F40B0C77474CAFD89845E768FAE3F6EEC0DF4575FCFE7094672C8C02169D744B415C617609"), 0);
var verifier = new Ed25519Signer();
verifier.init(false, publicKey);
verifier.update(msg, 0, msg.length);
var outcome = verifier.verifySignature(Hex.decode("674D11E432450118D70EA78673D5E31D5CC1AEC63DE0FF6284784876544BE340"));
System.out.println("Outcome: " + outcome);

Any help would be greatly appreciated

**Tags:** wallet

---

## 2 answers

### Answer by username_1 on 2022-11-03. Score: 1

After the [CIP-0030](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030) update you won't get the `publicKey` in the protected headers, but rather in the response object from `signData` directly, so the above answer won't work anymore.

Here is the example of the verification after the update: <https://github.com/MartinOndejka/cip-0008-verification>


---

### Answer by username_0 on 2022-04-04. Score: 0

First part of the solution can be found here:
https://github.com/bloxbean/cardano-client-examples/blob/cip008/src/main/java/com/bloxbean/cardano/client/examples/cip8/CIP8CBORParser.java
Code pasted here to keep track
package com.bloxbean.cardano.client.examples.cip8;

import co.nstant.in.cbor.CborDecoder;
import co.nstant.in.cbor.model.*;
import com.bloxbean.cardano.client.crypto.CryptoException;
import com.bloxbean.cardano.client.transaction.util.CborSerializationUtil;
import com.bloxbean.cardano.client.util.HexUtil;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;

import java.security.MessageDigest;
import java.security.Signature;
import java.util.List;

public class CIP8CBORParser {
    private static final EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);

    public void parse() throws Exception {
        //Payload = "hello"
        String coseSignMsgInHex = "845869a30127045820674d11e432450118d70ea78673d5e31d5cc1aec63de0ff6284784876544be3406761646472657373583901d2eb831c6cad4aba700eb35f86966fbeff19d077954430e32ce65e8da79a3abe84f4ce817fad066acc1435be2ffc6bd7dce2ec1cc6cca6cba166686173686564f44568656c6c6f5840a3b5acd99df5f3b5e4449c5a116078e9c0fcfc126a4d4e2f6a9565f40b0c77474cafd89845e768fae3f6eec0df4575fcfe7094672c8c02169d744b415c617609";

        //CBOR parsing starts here ###################
        List dataItemList  = CborDecoder.decode(HexUtil.decodeHexString(coseSignMsgInHex));

        List topArray = ((Array) dataItemList.get(0)).getDataItems();
        ByteString protectedHeaderBs = (ByteString) topArray.get(0);
        Map unprotectedMap = (Map) topArray.get(1);
        ByteString messageToSignBS = (ByteString) topArray.get(2);
        ByteString signatureArrayBS = (ByteString) topArray.get(3);

        byte[] message = messageToSignBS.getBytes();
        byte[] signature = signatureArrayBS.getBytes();

        System.out.println(new String(message));

        //parse protected header map bytestring
        List protectedHeaderMapDIList = CborDecoder.decode(protectedHeaderBs.getBytes());
        Map protectedHeaderMap = (Map) protectedHeaderMapDIList.get(0);

        ByteString publicKeyBS = (ByteString) protectedHeaderMap.get(new UnsignedInteger(4));
        byte[] publicKeyBytes = publicKeyBS.getBytes();

        ByteString addressBS = (ByteString)protectedHeaderMap.get(new UnicodeString("address"));
        System.out.println("Address >> " + HexUtil.encodeHexString(addressBS.getBytes()));
        //CBOR parsing ends her ###################

        //Create SignatureStructure. This is passed as message during signature verification
        Array sigStructArray = new Array();
        sigStructArray.add(new UnicodeString("Signature1"));
        sigStructArray.add(protectedHeaderBs);
        sigStructArray.add(new ByteString(new byte[0]));
        sigStructArray.add(messageToSignBS);

        byte[] messageToVerify = CborSerializationUtil.serialize(sigStructArray); //serialize
        //End SignatureStructure

        boolean verified = verify(messageToVerify, signature, publicKeyBytes);
        System.out.println("Verification status >> " + verified);
    }

    public boolean verify(byte[] message, byte[] signatureBytes, byte[] publicKeyBytes) {

        try{
            net.i2p.crypto.eddsa.EdDSAPublicKey publicKey = new net.i2p.crypto.eddsa.EdDSAPublicKey(new EdDSAPublicKeySpec(publicKeyBytes, spec));
            Signature signature = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
            signature.initVerify(publicKey);
            signature.setParameter(EdDSAEngine.ONE_SHOT_MODE);
            signature.update(message);
            return signature.verify(signatureBytes);
        }catch(Exception e){
            throw new CryptoException("Extended signing error", e);
        }
    }

    public static void main(String[] args) throws Exception {
        new CIP8CBORParser().parse();
    }
}

Kudos to @Satya
Second part missing is the adderss verificaiton/validation.
Will add as soon as it's done.


---

