简体   繁体   中英

raise ValueError(“Invalid DER input: insufficient data”) ValueError: Invalid DER input: insufficient data. How to solve this Error

I am trying to use ED25519 signing and verifying blockchain transactions in my blockchain project but I am getting a

ValueError "Invalid DER input: insufficient data

when I add the encode_dss_signature, and decode_dss_signature.

I am first converting the data into json format and then encoding it into (utf-8) format. Then when I try to decode the signature using decode_dss_signature . it gives the above Value Error.

import json
import uuid 
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives.asymmetric.utils import(
    encode_dss_signature,
    decode_dss_signature
)

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import serialization

class Wallet:
    """
    An individual wallet for a miner.
    Keeps track of the miners's balance.
    Allows a miner to authorize transactions.
    """
    def __init__(self):
        self.address = str(uuid.uuid4())[0:8] 
        self.private_key = Ed25519PrivateKey.generate()
        self.public_key = self.private_key.public_key()
        self.serialize_public_key()

    def sign(self, data):
        """
        Generate a signature based on the data using the local private key.
        """
        return decode_dss_signature(self.private_key.sign(
            json.dumps(data).encode('utf-8')
        ))


    def serialize_public_key(self):
        """
        Reset the public key to its serialized version.
        """
        self.public_key = self.public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        ).decode('utf-8')

        print(f'\n-- self.public_key: {self.public_key}')


    @staticmethod
    def verify(public_key, signature, data):
        """
        Verify signature based on original public_key and data.
        """

        deserialized_public_key = serialization.load_pem_public_key(
            public_key.encode('utf-8')
        )

        print(f'\n--signature: {signature}\n')
        (r, s) = signature

        try:
            deserialized_public_key.verify(
                encode_dss_signature(r, s), 
                json.dumps(data).encode('utf-8')
            )

            return True

        except InvalidSignature:
            return False


def main():
    wallet = Wallet()
    print(f'wallet.__dict__: {wallet.__dict__}')

    data = { 'foo':'bar' }

    signature = wallet.sign(data)
    print(f'signature: {signature}')

    sign_verification = Wallet.verify(wallet.public_key, signature, data)
    print(f'sign_verification: {sign_verification}')

   sign_verify_failed = Wallet.verify(Wallet().public_key, signature, data)
   print(f'sign_verify_failed: {sign_verify_failed}')

if __name__ == '__main__':
    main()

I found across my testing that depending on what private_key was generated by Ed25519PrivateKey I ended up getting a different error.

By simply running your program as posted 10,000 times I got all of the following ValueError types:

Value Error Message Number of Occurrences Percent Occurrence
Invalid DER input: insufficient data 7193 71.93%
Invalid DER input: unexpected tag 2389 23.89%
Invalid DER input: unexpected high tag number 334 3.34%
Invalid DER input: indefinite length form is not allowed in DER 39 0.39%
Invalid DER input: length was not minimally-encoded 31 0.31%
Invalid DER input: trailing data 14 0.14%

You can try for yourself with:

from collections import Counter


def main():
    c = Counter()
    for i in range(10_000):
        try:
            wallet = Wallet()
            data = { 'foo':'bar' }
            wallet.sign(data)
        except ValueError as e:
            c.update([str(e)])
    print(c)

While, cryptography.hazmat.primitives.asymmetric.utils.decode_dss_signature(signature) theoretically

Takes in signatures generated by the DSA/ECDSA signers and returns a tuple (r, s). These signatures are ASN.1 encoded Dss-Sig-Value sequences (as defined in RFC 3279)

And while theoretically

Ed25519 is an elliptic curve signing algorithm using EdDSA and Curve25519. If you do not have legacy interoperability concerns then you should strongly consider using this signature algorithm.

In terms of this program, the value produced by sign does not conform to the expected input of decode_dss_signature

I tried all possible encodings of the public and private keys before passing it into decode_dss_signature . While changing the encoding and format did change the rates and types of ValueError received, I still consistently received the same type of error.

There may be a way to ensure that the generated private key conforms to the expected standard for decode_dss_signature , but I was unable to find much in terms of documentation or use cases for this particular function.

Since encode_dss_signature and decode_dss_signature do not behave as expected with ED25519 , I ended up directly returning the results from sign and verify .

import json
import uuid

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey


class Wallet:
    """
    An individual wallet for a miner.
    Keeps track of the miners's balance.
    Allows a miner to authorize transactions.
    """

    def __init__(self):
        self.address = str(uuid.uuid4())[0:8]
        self.private_key = Ed25519PrivateKey.generate()
        self.public_key = self.private_key.public_key()
        self.serialize_public_key()

    def sign(self, data):
        """
        Generate a signature based on the data using the local private key.
        """
        return self.private_key.sign(
            json.dumps(data).encode('utf-8')
        )

    def serialize_public_key(self):
        """
        Reset the public key to its serialized version.
        """
        self.public_key = self.public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        ).decode('utf-8')

    @staticmethod
    def verify(public_key, signature, data):
        """
        Verify signature based on original public_key and data.
        """

        deserialized_public_key = serialization.load_pem_public_key(
            public_key.encode('utf-8')
        )

        try:
            deserialized_public_key.verify(
                signature,
                json.dumps(data).encode('utf-8')
            )
            return True
        except InvalidSignature:
            return False


def main():
    wallet = Wallet()

    data = {'foo': 'bar'}

    signature = wallet.sign(data)
    print(f'signature: {signature}')

    sign_verification = Wallet.verify(wallet.public_key, signature, data)
    print(f'sign_verification: {sign_verification}')

    sign_verify_failed = Wallet.verify(Wallet().public_key, signature, data)
    print(f'sign_verify_failed: {sign_verify_failed}')


if __name__ == '__main__':
    main()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM