Search code examples
javasecuritydigital-signaturebouncycastleprivate-key

java.security.spec.InvalidKeySpecException: encoded key spec not recognized: failed to construct sequence from byte[] by generating ECDSA Signature


I created a simple UserInterface that allows a user to send a transaction, similar to bitcoin. Among other things, the user must enter his private key (this is already encoded!). However, I have difficulties to create a signature from it. My private Key is decoded like this: SHA3Helper.digestToHex( ( ( BCECPrivateKey ) keyPair.getPrivate( ) ).getD( ).toByteArray( ) ) ); SHA3Helper is just to convert a byteArray to a String and acutally not very important here. I also use the secp256k1 elliptic curve. Here is the method I use to create the signature:

public static byte[] GenerateSignature(String transaction, byte[] keyPriv) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        byte[] privateKeyBytes = keyPriv;
        KeyFactory kf = KeyFactory.getInstance("ECDSA");
        PrivateKey pKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
        Signature ecdsaSign = Signature.getInstance("ECDSA", "BC");
        ecdsaSign.initSign(pKey);
        ecdsaSign.update(transaction.getBytes("UTF-8"));
        byte[] signature = ecdsaSign.sign();
        System.out.println(signature.toString());
        return signature;
    }

Heres the simple method for reading the users input

@FXML
    void submitPressed(ActionEvent event) {
        System.out.println("Submit Pressed");
        byte[] sender = SHA3Helper.hexToDigest(senderField.getText());
        byte[] receiver = SHA3Helper.hexToDigest(receiverField.getText());
        double amount = Double.parseDouble(amountField.getText());
        double tfbp = Double.parseDouble(tfbpField.getText());
        double tfl = Double.parseDouble(tflField.getText());
        byte[] privateKey = SHA3Helper.hexToDigest(keyField.getText());
        Transaction transaction = new Transaction(sender, receiver, amount, 0, tfbp, tfl);
        System.out.println(transaction.getAmount());
        try {
            byte[] signature = SignatureHelper.GenerateSignature(transaction.asJSONString(), privateKey);
            transaction.setSignature(signature);
            System.out.println("Signatur: " + transaction.getSignature());
        } catch (Exception e) {     
            e.printStackTrace();
        }
        DependencyManager.getPendingTransactions().addPendingTransaction(transaction);
    
    }

As you can see, I convert the privateKey string directly into a byte array and pass this to my generateSignature method.

Full Stack Trace:

java.security.spec.InvalidKeySpecException: encoded key spec not recognized: failed to construct sequence from byte[]: DEF length 112 object truncated by 82
    at org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi.engineGeneratePrivate(Unknown Source)
    at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.engineGeneratePrivate(Unknown Source)
    at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:389)
    at main.utils.SignatureHelper.GenerateSignature(SignatureHelper.java:65)
    at main.Controller.submitPressed(Controller.java:50)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at com.sun.javafx.reflect.Trampoline.invoke(MethodUtil.java:77)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at com.sun.javafx.reflect.MethodUtil.invoke(MethodUtil.java:275)
    at com.sun.javafx.fxml.MethodHelper.invoke(MethodHelper.java:84)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1852)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1724)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8923)
    at javafx.scene.control.Button.fire(Button.java:203)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:207)
    at com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:247)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3894)
    at javafx.scene.Scene.processMouseEvent(Scene.java:1887)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2620)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:411)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:301)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:450)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:449)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:551)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
    at java.base/java.lang.Thread.run(Thread.java:1589)

It seems the error is probably in the conversion but I can't find it.


Solution

  • Try this to reproduce the privateKey from the decodedBytes:

     public static PrivateKey getPrivateKeyFromBytes( byte[] privateKey ){
        PrivateKey result;
        try
        {
            ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec( CURVE_NAME );
            KeyFactory kf = KeyFactory.getInstance( ALGORITHM, PROVIDER );
            ECNamedCurveSpec params =
                new ECNamedCurveSpec( CURVE_NAME, spec.getCurve( ), spec.getG( ), spec.getN( ) );
            BigInteger s = new BigInteger(1, privateKey);
            ECPrivateKeySpec pubKeySpec = new ECPrivateKeySpec(s, params);
            result = kf.generatePrivate( pubKeySpec );
        }
        catch ( Exception e )
        {
            result = null;
        }
    
        return result;
    }