Search code examples
c#.net-coreutf-8ecdsarsa-sha256

Problems to write a byte array of a signed hash with a private key in a text file and get it back as the same format


I'm writing a bytes array to a text file of a signed hash, that I first convert to a base64 string and convert to a bytes array again with the encoding UTF-8 before writing to the text file, my current problem is that when I get the bytes back I don't know how to convert to the original format to validate my signed hash with the public key, does anybody know to convert it back?

This is how I convert my original bytes to be able to write in the text file:

        public static byte[] ConvertToBase64(byte[] bytes)
        {
            string base64 = Convert.ToBase64String(bytes);
            return Encoding.UTF8.GetBytes(base64);
        }

This is how I sign the hash:

        private byte[] signData(byte[] dataValue)
        {
            X509Certificate2 privateKey = new X509Certificate2(privateKeyfileName, password);

            //Encryting/Signing a hash
            using (ECDsa ecdsa = privateKey.GetECDsaPrivateKey())
            {
                if (ecdsa == null) throw new Exception("Not an ECDSA cert, or has no private key");

                return ecdsa.SignData(dataValue, HashAlgorithmName.SHA256);
            }
        }

This is how I create the hash:

        // The cryptographic service provider.
        private SHA256 Sha256 = SHA256.Create();

        // Compute the file's hash.
        private byte[] GetHashSha256FromFile(string filename)
        {
            using (FileStream stream = File.OpenRead(filename))
            {
                return Sha256.ComputeHash(stream);
            }
        }

This is how I was supposed to validate the signed hash if I could get the value from my original signed hash:

        private bool verifyData(byte[] dataValue, byte[] dataSigned)
        {
            byte[] mycertCer = Properties.Resources.mycertCer;
            X509Certificate2 publicKey = new X509Certificate2(mycertCer, password);

            //Checking the hash and signature
            using (ECDsa ecdsa = publicKey.GetECDsaPublicKey())
            {
                if (ecdsa == null) throw new Exception("Not an ECDSA cert, or has no private key");

                return ecdsa.VerifyData(dataValue, dataSigned, HashAlgorithmName.SHA256);
            }
        }

I'll appreciate any help, let me know if you need more details.


Solution

  • The signature is binary data, so you could store it as raw bytes (on file ending with any extension .bin for example)

    public static byte[] readFileBytes(String filepath) throws Exception {
        return Files.readAllBytes(Paths.get(filepath));
    }
    
    public static void writeFileBytes(String filepath, byte[] input) throws Exception {
        try (FileOutputStream fos = new FileOutputStream(filepath)) {
            fos.write(input);
        }
    }
    

    if you really want to store this binary/bytes array into text file, then you have to encoded safely by using base64 or hex:

    public static String fromBytesToBase64(byte[] dataBytes) {
        return Base64.getEncoder().encodeToString(dataBytes);
    }
    
    public static byte[] fromBase64ToBytes(String base64String) {
        return Base64.getDecoder().decode(base64String);
    }
    

    The flow will be like:

    byte[] signature = getTheSignatureAfterSignOperation();
    String signatureInBase64 = fromBytesToBase64(signature);
    saveToTextfile(signatureInBase64, "anyFile.txt");
    
    // Other side
    String signatureBase64 = readTextFile("anyFile.txt");
    byte[] originalSignature = fromBase64ToBytes(signatureBase64);
    doVerficiation(originalSignature);