I'm trying to verify a signature on an XML using the java Signature class but it's always returning false.
The XML is returned by a SAML service.
Here is my code:
public static boolean test() throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, CertificateException {
String rawCert = "MIIE4zCCA8ugAwIBAgIFAIunqocwDQYJKoZIhvcNAQELBQAwfjEYMBYGCSqGSIb3DQEJARMJaXRAYW1hLnB0MQswCQYDVQQGEwJQVDEPMA0GA1UEBxMGTGlzYm9hMQwwCgYDVQQKEwNBTUExCzAJBgNVBAsTAklUMSkwJwYDVQQDEyBzYW1sLnByZXByb2QuYXV0ZW50aWNhY2FvLmdvdi5wdDAeFw0yMjAyMDIxNTIyMzFaFw0yNjA0MjIxNTIyMzFaMIGmMQswCQYDVQQLEwJJVDE5MDcGA1UEChMwQUdFTkNJQSBQQVJBIEEgTU9ERVJOSVpBQ0FPIEFETUlOSVNUUkFUSVZBLCBJLlAuMQ8wDQYDVQQHEwZMaXNib24xDzANBgNVBAgTBkxpc2JvbjELMAkGA1UEBhMCUFQxLTArBgNVBAMTJGlkcC5zYW1sLnByZXByb2QuYXV0ZW50aWNhY2FvLmdvdi5wdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALYNe0uVeWxQenErd8CndyBJakERq+ZfFLGhIiCIG03Kk3P7ZXacKcj7KQk6h6xNDRccrgJjERMb0jhQPxNc1YfGs9gugYJjMVqdyhbPrOLw1gC6jOuZYCFKqpK3KvNLt5uFL+svJrlbCme04InkJGI+tWpMn18FZCNabgvr96MPdEx1UkiUd8/LvfNwrvdIcRzjncS8rDNN/aoN+LOrMBciWup9IfclcTQu21QnJu5bW1m6a5RarB+2VExGhBuO05V9Hlu1GgR+ISOT93OxW8w8Y297FJcbOtGn1DS+BmEP4nXw1Z5tLp1TglLJqJyjPUbQH/RTHdEwwghE7t2LriUCAwEAAaOCAT0wggE5MIGiBgNVHSMEgZowgZeAFIqEGWsGURditfEV0gDuoBPL+ns5oXekdTBzMRgwFgYJKoZIhvcNAQkBEwlpdEBhbWEucHQxCzAJBgNVBAYTAlBUMQ8wDQYDVQQHEwZMaXNib2ExDDAKBgNVBAoTA0FNQTELMAkGA1UECxMCSVQxHjAcBgNVBAMTFUF1dGVudGljYWNhby5Hb3YgUmFpeoIGAWHCrFBGMB0GA1UdDgQWBBQPx8QxxuPf/9Rahh21vZWGYa9+wDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAvBgNVHREEKDAmgiRpZHAuc2FtbC5wcmVwcm9kLmF1dGVudGljYWNhby5nb3YucHQwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwEgYKKwYBBAGC9DQBAQQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEA1T3ZLmK9ZdITIUjy0EzGF8+art8NoESs4JCNmzSKcuEqWZpWIWoMmo5mhsCwgKo4DmtL42rFqDbYghJYCaq/ENZ+6dgRJmnZNTJqT2bqa5F4kQM4yNMZfjBwF1qRWUMF/mRay5rQVOe81zqmUCNguiGCWFAnTtxTED6HmO+/ci60fuW6BcU06HI8hmB8km/wwYfQe8gsQ9X/7INHe5XWZ1ZqT3X+yz6sNiWiKIk18b2VJ+Ml7ZMZr202YU5i8VjKCzTEA7e/2eEWLVZMIvKRm+FHNbKqpcmVxysGa9kDanv1id4CIv+u7H4WBMu3Dsi1GdI1WpFxuIQcblZfgM8odw==";
byte [] decoded = Base64.getDecoder().decode(rawCert);
Certificate cert = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(decoded));
PublicKey publicKey = cert.getPublicKey();
String sigValue = "muuNQW0vr/YE31Mjls4UCBZLlavnsAHp3EarT2p5NLYIU6C32Zb0jeQ/c+zvK5CsNG/ld836R78Ji4NFJiuWEPvSIqB7MKeoqpNolmOZdVbu6ZRRJLCa/awwLizfbPAWv+JQkT+aZX6pkVgS71q1LsF3NtAgIqOdJyBHtBFoFvuTRKZx7JmDwRttPtSL8lRMO3v+h0LyTIPNB0KFGfCuzrfUFOR3RrzZauiWOjJChN1uhKaF4M1ivnCxaSFVol7vctaPkNJgyORgh7UZjqXOA2WA3SaIbKaf6L3MJfCKvLZiHB49OvWTIEOKF5wOlRat5oL5RiqW6/imH4cZakVkWQ==";
byte[] sigBytes = Base64.getDecoder().decode(sigValue);
String signatureType = "SHA1withRSA";
String content ="PFJlc3BvbnNlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhtbG5zOnhzZD0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIElEPSJfZTg1ZDgwYmItMGI1My00Y2MzLTgzYTEtOTQ4OWU4ZTA4NzA5IiBJblJlc3BvbnNlVG89Il9jMzg1ZjVkMi1kNWI4LTQ1YzItODJmZS1kODcwMGMzODQ0Y2QiIFZlcnNpb249IjIuMCIgSXNzdWVJbnN0YW50PSIyMDIyLTAzLTA3VDExOjI3OjQ2Ljg3NTUwMjdaIiBEZXN0aW5hdGlvbj0iaHR0cDovL2xvY2FsaG9zdDo4MDgwL3dlYi9ndWVzdC9jbWQ/cF9wX2lkPUNNRExvZ2luJmFtcDtwX3BfbGlmZWN5Y2xlPTEmYW1wO3BfcF9zdGF0ZT1ub3JtYWwmYW1wO3BfcF9tb2RlPXZpZXcmYW1wO19DTURMb2dpbl9qYXZheC5wb3J0bGV0LmFjdGlvbj1hY3Rpb25Mb2dpblNBTUxSZXNwb25zZSZhbXA7X0NNRExvZ2luX2Zyb21Mb2dpblBhZ2U9eWVzJmFtcDtwX2F1dGg9Rnl3ZERRcHoiIENvbnNlbnQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjb25zZW50OnVuc3BlY2lmaWVkIiB4bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj4NCiAgPElzc3VlciB4bWxucz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI+aHR0cHM6Ly9hdXRlbnRpY2FjYW8uY2FydGFvZGVjaWRhZGFvLnB0PC9Jc3N1ZXI+PFNpZ25hdHVyZSB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyI+PFNpZ25lZEluZm8+PENhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAxL1JFQy14bWwtYzE0bi0yMDAxMDMxNSIgLz48U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3JzYS1zaGExIiAvPjxSZWZlcmVuY2UgVVJJPSIjX2U4NWQ4MGJiLTBiNTMtNGNjMy04M2ExLTk0ODllOGUwODcwOSI+PFRyYW5zZm9ybXM+PFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIiAvPjxUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8+PC9UcmFuc2Zvcm1zPjxEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgLz48RGlnZXN0VmFsdWU+amRQQTJpRnhOQXA3dnpXNlF6TkJVakhkM2s4PTwvRGlnZXN0VmFsdWU+PC9SZWZlcmVuY2U+PC9TaWduZWRJbmZvPjxTaWduYXR1cmVWYWx1ZT5ZTlVGUExuWWhRV2gvT3BwdzV6bUoreGNjZTZxTjd3VjJlT0ZtbW8rQUZNTVVJR01LbHVCdE9kOGVIS1BGbVIveEdaVUdIdkkveU9BRVVXdDhjNytDdkxrSjRvK1BhYVZ1K1k0YW82Snhoby8wV3M4c1ZUM3Z0dUYyMk44MTJyZ0ZISHh1RFhKWVVLMHlEN2FqRGhFUjJueGJSckxmVlY3Zk5ZOU1oWERnY2tmL0RheE95cEQ0QXg1WnJnMkp4cDgwZTJRa29QOXlXMkpjSUs4bkczTEFBTzRKWThBa3FHMnZ1TWJPYk5kV2gzS1R3VnMvV2pEN3hpVUdRY01ScXFDZ0xaTER1MS92YmJaQ2xObk5UejBnRUNDWGVXaXV2RVpieFlCRWs1STArOW56cW9DaWVlTjNFdFhLclJ0MkdTN080bVl3VmN4dVRkZHJmTDJ6dE9vYUE9PTwvU2lnbmF0dXJlVmFsdWU+PEtleUluZm8+PFg1MDlEYXRhPjxYNTA5Q2VydGlmaWNhdGU+TUlJRTR6Q0NBOHVnQXdJQkFnSUZBSXVucW9jd0RRWUpLb1pJaHZjTkFRRUxCUUF3ZmpFWU1CWUdDU3FHU0liM0RRRUpBUk1KYVhSQVlXMWhMbkIwTVFzd0NRWURWUVFHRXdKUVZERVBNQTBHQTFVRUJ4TUdUR2x6WW05aE1Rd3dDZ1lEVlFRS0V3TkJUVUV4Q3pBSkJnTlZCQXNUQWtsVU1Ta3dKd1lEVlFRREV5QnpZVzFzTG5CeVpYQnliMlF1WVhWMFpXNTBhV05oWTJGdkxtZHZkaTV3ZERBZUZ3MHlNakF5TURJeE5USXlNekZhRncweU5qQTBNakl4TlRJeU16RmFNSUdtTVFzd0NRWURWUVFMRXdKSlZERTVNRGNHQTFVRUNoTXdRVWRGVGtOSlFTQlFRVkpCSUVFZ1RVOUVSVkpPU1ZwQlEwRlBJRUZFVFVsT1NWTlVVa0ZVU1ZaQkxDQkpMbEF1TVE4d0RRWURWUVFIRXdaTWFYTmliMjR4RHpBTkJnTlZCQWdUQmt4cGMySnZiakVMTUFrR0ExVUVCaE1DVUZReExUQXJCZ05WQkFNVEpHbGtjQzV6WVcxc0xuQnlaWEJ5YjJRdVlYVjBaVzUwYVdOaFkyRnZMbWR2ZGk1d2REQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQ0FRb0NnZ0VCQUxZTmUwdVZlV3hRZW5FcmQ4Q25keUJKYWtFUnErWmZGTEdoSWlDSUcwM0trM1A3WlhhY0tjajdLUWs2aDZ4TkRSY2NyZ0pqRVJNYjBqaFFQeE5jMVlmR3M5Z3VnWUpqTVZxZHloYlByT0x3MWdDNmpPdVpZQ0ZLcXBLM0t2Tkx0NXVGTCtzdkpybGJDbWUwNElua0pHSSt0V3BNbjE4RlpDTmFiZ3ZyOTZNUGRFeDFVa2lVZDgvTHZmTndydmRJY1J6am5jUzhyRE5OL2FvTitMT3JNQmNpV3VwOUlmY2xjVFF1MjFRbkp1NWJXMW02YTVSYXJCKzJWRXhHaEJ1TzA1VjlIbHUxR2dSK0lTT1Q5M094Vzh3OFkyOTdGSmNiT3RHbjFEUytCbUVQNG5YdzFaNXRMcDFUZ2xMSnFKeWpQVWJRSC9SVEhkRXd3Z2hFN3QyTHJpVUNBd0VBQWFPQ0FUMHdnZ0U1TUlHaUJnTlZIU01FZ1pvd2daZUFGSXFFR1dzR1VSZGl0ZkVWMGdEdW9CUEwrbnM1b1hla2RUQnpNUmd3RmdZSktvWklodmNOQVFrQkV3bHBkRUJoYldFdWNIUXhDekFKQmdOVkJBWVRBbEJVTVE4d0RRWURWUVFIRXdaTWFYTmliMkV4RERBS0JnTlZCQW9UQTBGTlFURUxNQWtHQTFVRUN4TUNTVlF4SGpBY0JnTlZCQU1URlVGMWRHVnVkR2xqWVdOaGJ5NUhiM1lnVW1GcGVvSUdBV0hDckZCR01CMEdBMVVkRGdRV0JCUVB4OFF4eHVQZi85UmFoaDIxdlpXR1lhOSt3REFKQmdOVkhSTUVBakFBTUFzR0ExVWREd1FFQXdJRjREQXZCZ05WSFJFRUtEQW1naVJwWkhBdWMyRnRiQzV3Y21Wd2NtOWtMbUYxZEdWdWRHbGpZV05oYnk1bmIzWXVjSFF3RmdZRFZSMGxBUUgvQkF3d0NnWUlLd1lCQlFVSEF3RXdFZ1lLS3dZQkJBR0M5RFFCQVFRRUF3SUNCREFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBMVQzWkxtSzlaZElUSVVqeTBFekdGOCthcnQ4Tm9FU3M0SkNObXpTS2N1RXFXWnBXSVdvTW1vNW1oc0N3Z0tvNERtdEw0MnJGcURiWWdoSllDYXEvRU5aKzZkZ1JKbW5aTlRKcVQyYnFhNUY0a1FNNHlOTVpmakJ3RjFxUldVTUYvbVJheTVyUVZPZTgxenFtVUNOZ3VpR0NXRkFuVHR4VEVENkhtTysvY2k2MGZ1VzZCY1UwNkhJOGhtQjhrbS93d1lmUWU4Z3NROVgvN0lOSGU1WFdaMVpxVDNYK3l6NnNOaVdpS0lrMThiMlZKK01sN1pNWnIyMDJZVTVpOFZqS0N6VEVBN2UvMmVFV0xWWk1JdktSbStGSE5iS3FwY21WeHlzR2E5a0RhbnYxaWQ0Q0l2K3U3SDRXQk11M0RzaTFHZEkxV3BGeHVJUWNibFpmZ004b2R3PT08L1g1MDlDZXJ0aWZpY2F0ZT48L1g1MDlEYXRhPjwvS2V5SW5mbz48L1NpZ25hdHVyZT4NCiAgPEV4dGVuc2lvbnM+DQogICAgPGZhOkZBQUFMZXZlbCB4bWxuczpmYT0iaHR0cDovL2F1dGVudGljYWNhby5jYXJ0YW9kZWNpZGFkYW8ucHQvYXRyaWJ1dG9zIj4zPC9mYTpGQUFBTGV2ZWw+DQogIDwvRXh0ZW5zaW9ucz4NCiAgPFN0YXR1cz4NCiAgICA8U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPg0KICA8L1N0YXR1cz4NCiAgPEFzc2VydGlvbiBWZXJzaW9uPSIyLjAiIElEPSJfMTYyZTI4YzItMzU1MC00MGViLTlhMmQtMDNjMmQ3YWFhOGRlIiBJc3N1ZUluc3RhbnQ9IjIwMjItMDMtMDdUMTE6Mjc6NDYuODc1NTAyN1oiIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj4NCiAgICA8SXNzdWVyPmh0dHBzOi8vYXV0ZW50aWNhY2FvLmNhcnRhb2RlY2lkYWRhby5wdDwvSXNzdWVyPg0KICAgIDxTdWJqZWN0Pg0KICAgICAgPE5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OnVuc3BlY2lmaWVkIj51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDp1bnNwZWNpZmllZDwvTmFtZUlEPg0KICAgICAgPFN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj4NCiAgICAgICAgPFN1YmplY3RDb25maXJtYXRpb25EYXRhIE5vdE9uT3JBZnRlcj0iMjAyMi0wMy0wN1QxMTozMjo0NloiIFJlY2lwaWVudD0icWFwb3J0YWwuYXNjZW5kaS5wdCIgSW5SZXNwb25zZVRvPSJfYzM4NWY1ZDItZDViOC00NWMyLTgyZmUtZDg3MDBjMzg0NGNkIiBBZGRyZXNzPSJodHRwczovL2lnbm9yZS5tb3Jkb21vLmdvdi5wdCIgLz4NCiAgICAgIDwvU3ViamVjdENvbmZpcm1hdGlvbj4NCiAgICA8L1N1YmplY3Q+DQogICAgPENvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDIyLTAzLTA3VDExOjI3OjQ2WiIgTm90T25PckFmdGVyPSIyMDIyLTAzLTA3VDExOjMyOjQ2WiI+DQogICAgICA8QXVkaWVuY2VSZXN0cmljdGlvbj4NCiAgICAgICAgPEF1ZGllbmNlPnFhcG9ydGFsLmFzY2VuZGkucHQ8L0F1ZGllbmNlPg0KICAgICAgPC9BdWRpZW5jZVJlc3RyaWN0aW9uPg0KICAgICAgPE9uZVRpbWVVc2UgLz4NCiAgICA8L0NvbmRpdGlvbnM+DQogICAgPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAyMi0wMy0wN1QxMToyNzo0Ni44NzU1MDI3WiI+DQogICAgICA8QXV0aG5Db250ZXh0Pg0KICAgICAgICA8QXV0aG5Db250ZXh0RGVjbCB4c2k6dHlwZT0ieHNkOnN0cmluZyIgLz4NCiAgICAgIDwvQXV0aG5Db250ZXh0Pg0KICAgIDwvQXV0aG5TdGF0ZW1lbnQ+DQogICAgPEF0dHJpYnV0ZVN0YXRlbWVudD4NCiAgICAgIDxBdHRyaWJ1dGUgTmFtZT0iaHR0cDovL2ludGVyb3AuZ292LnB0L01EQy9DaWRhZGFvL05vbWVDb21wbGV0byIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiIGQ0cDE6QXR0cmlidXRlU3RhdHVzPSJBdmFpbGFibGUiIHhtbG5zOmQ0cDE9Imh0dHA6Ly9hdXRlbnRpY2FjYW8uY2FydGFvZGVjaWRhZGFvLnB0L2F0cmlidXRvcyI+DQogICAgICAgIDxBdHRyaWJ1dGVWYWx1ZSB4c2k6dHlwZT0ieHNkOnN0cmluZyI+U8OpcmdpbyBGZXJuYW5kZXM8L0F0dHJpYnV0ZVZhbHVlPg0KICAgICAgPC9BdHRyaWJ1dGU+DQogICAgICA8QXR0cmlidXRlIE5hbWU9Imh0dHA6Ly9pbnRlcm9wLmdvdi5wdC9NREMvQ2lkYWRhby9OSUYiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIiBkNHAxOkF0dHJpYnV0ZVN0YXR1cz0iQXZhaWxhYmxlIiB4bWxuczpkNHAxPSJodHRwOi8vYXV0ZW50aWNhY2FvLmNhcnRhb2RlY2lkYWRhby5wdC9hdHJpYnV0b3MiPg0KICAgICAgICA8QXR0cmlidXRlVmFsdWUgeHNpOnR5cGU9InhzZDpzdHJpbmciPjIxOTMxNjI1MjwvQXR0cmlidXRlVmFsdWU+DQogICAgICA8L0F0dHJpYnV0ZT4NCiAgICA8L0F0dHJpYnV0ZVN0YXRlbWVudD4NCiAgPC9Bc3NlcnRpb24+DQo8L1Jlc3BvbnNlPg==";
byte[] contentBytes = Base64.getDecoder().decode(content);
Signature sig = Signature.getInstance(signatureType);
sig.initVerify(publicKey);
sig.update(contentBytes);
return sig.verify(sigBytes);
}
Am I doing something wrong here or is the XML really badly signed? I don't control the server that is sending the response and apparently everything is well on their side.
I am not sure where you got the sigValue
XML signature verification uses the information from the XML to do the verification and the Signature value in there does not match the value that you have.
I used perl's XML-Sig and verified the XML with no issue using the rawcert and content to verify the XML using the SignatureValue in the XML
When verifying a signature using Signature.verify I receive an "Invalid encoding for signature" exception.
When verifying same signature using Azure service, the signature is verified.
I have a hash-data (SHA-256), a public key, and a signature that I'm trying to verify.
The signature was received using com.microsoft.azure.keyvault.KeyVaultClient.sign method, with signing algorithm "ES256".
This works (using ES256 algorithm) :
com.microsoft.azure.keyvault.KeyVaultClient keyVaultClient;
String keyPairIdentifier;
boolean verify(byte[] hashData, byte[] signature, JsonWebKeySignatureAlgorithm signingAlgorithm) {
com.microsoft.azure.keyvault.models.KeyVerifyResult result = keyVaultClient.verify(keyPairIdentifier, signingAlgorithm, hashData, signature);
return result.value().booleanValue();
}
This fails (certificate holds same public key that is stored in Azure keyvault):
Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");
ecdsaSign.initVerify(certificate.getPublicKey());
ecdsaSign.update(hashData);
ecdsaSign.verify(signature)
Expected result - true (signature is verified)
Actual result:
java.security.SignatureException: Could not verify signature
at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:325)
at java.security.Signature$Delegate.engineVerify(Signature.java:1222)
at java.security.Signature.verify(Signature.java:655)
at TestKV.KeyVault.VerifyDPSignature.verifySignatureUsingCertificate(VerifyDPSignature.java:143)
at TestKV.KeyVault.VerifyDPSignature.main(VerifyDPSignature.java:104)
Caused by: java.security.SignatureException: Invalid encoding for signature
at sun.security.ec.ECDSASignature.decodeSignature(ECDSASignature.java:400)
at sun.security.ec.ECDSASignature.engineVerify(ECDSASignature.java:322)
... 4 more
Caused by: java.io.IOException: Sequence tag error
at sun.security.util.DerInputStream.getSequence(DerInputStream.java:330)
at sun.security.ec.ECDSASignature.decodeSignature (ECDSASignature.java:376)
dave_thompson_085 - thanks!
There were a few mistakes in the code you attached, the tags of the signature parts should be 0x02, not 0x30, and you didn't increase o after copying the first part.
This is the code after the changes:
byte[] r = new BigInteger(1,Arrays.copyOfRange(signature,0,32)).toByteArray();
byte[] s = new BigInteger(1,Arrays.copyOfRange(signature,32,64)).toByteArray();
byte[] der = new byte[6+r.length+s.length];
der[0] = 0x30; // Tag of signature object
der[1] = (byte)(der.length-2); // Length of signature object
int o = 2;
der[o++] = 0x02; // Tag of ASN1 Integer
der[o++] = (byte)r.length; // Length of first signature part
System.arraycopy (r,0, der,o, r.length);
o += r.length;
der[o++] = 0x02; // Tag of ASN1 Integer
der[o++] = (byte)s.length; // Length of second signature part
System.arraycopy (s,0, der,o, s.length);
After the format change I didn't get the "Sequence tag error" exception. But the verification still failed.
Thanks!
Azure does JWS which simply concatenates fixed-size I2OSP of r and s but Java JCE, like most but not all standards, uses ASN.1 DER encoding e.g. rfc3279 (caveat: there are now OIDs for ECDSA with other hashes).
To convert JWS/plain to DER, see my (cross) https://security.stackexchange.com/questions/174095/convert-ecdsa-signature-from-plain-to-der-format for a C approach, but Java makes it easier because BigInteger does half the work for you:
// byte[64] plain contains the JWS-style r,s (de-base64-ed if necessary)
byte[] r = new BigInteger(1,Arrays.copyOfRange(plain,0,32)).toByteArray();
byte[] s = new BigInteger(1,Arrays.copyOfRange(plain,32,64)).toByteArray();
byte[] der = new byte[6+r.length+s.length]; der[0] = 0x30; der[1] = der.length-2; int o = 2;
der[o++] = 2; der[o++] = (byte)r.length; System.arraycopy (r,0, der,o, r.length); o+=r.length;
der[o++] = 2; der[o++] = (byte)s.length; System.arraycopy (s,0, der,o, s.length); //o+=s.length;
2020-05 corrected and added: also Java 9 up handles this directly using algoirthm names like SHA256withECDSAinP1363format, and on all versions of Java if you add BouncyCastle it does so using names like SHA256withPLAIN-ECDSA or SHA256withCVC-ECDSA. See how to specify signature length for java.security.Signature sign method and Java ECDSAwithSHA256 signature with inconsistent length .
I just had to first decode the signature's raw bytes to Base64 in my case.
byte[] signatureBytes = Base64.getDecoder().decode(signature.getBytes());
byte[] r = new BigInteger(1,Arrays.copyOfRange(signatureBytes,0,32)).toByteArray();
byte[] s = new BigInteger(1,Arrays.copyOfRange(signatureBytes,32,64)).toByteArray();
hi i'm trying to decode two strings then use the return result (byte[]) then put it in a Biginteger constructor Like this :
BigInteger bigInteger1 = new BigInteger(1, Base64.decode(myString1,0));
BigInteger bigInteger2 = new BigInteger(1, Base64.decode(myString2,0));
then put this BigIntegers on a java.security.KeyFactory class to create a RSAPublicKey like This :
KeyFactory.getInstance(ALG).generatePublic(new RSAPublicKeySpec(bigInteger1,bigInteger2));
then use my public key to encode a string Like this :
public static String encrypt(PublicKey publicKey, String str) {
Cipher instance = Cipher.getInstance(ALG);
instance.init(1, publicKey);
Base64.encodeToString(instance.doFinal(str.getBytes()), 2);
}
on PHP. I achieve this goal with android but when I want to do it with PHP I have a lot of problems even on the start when I want to decode my string in PHP with this code :
$encoded = base64_decode($base,true);
$decoded = utf8_decode(base64_decode($encoded));
I will get this string:??2?]????5N?[??S
but in android, the decoded string is totally different and always stay the same result
I tried to do this job on JSP but it's really hard to learn a new language and I don't have the time.
Can I do this project in spring boot? I have the codes for java
please, somebody, help me.
You're decoding string twice. You should try :
$encoded = base64_encode($base); // and not base64_decode
$decoded = base64_decode($encoded); // will be $base
utf8_decode is converting a string with ISO-8859-1 characters encoded with UTF-8 to single-byte ISO-8859-1. Are you sure you're needing it ?
In PHP, you can use intval to performs BigInteger() but I'm not sure you won't be facing an integer overflow.
Finally, OpenSSL library will certainly do the job for key generation and encryption.
So I've been reading and reading and looking at examples and...failing miserably. Here's my situation:
I have a CMK in KMS and I've generated a data key, like so:
$ aws kms generate-data-key --key-id 64a62e3e-7e38-4f86-8ef2-3d00929e6260 --key-spec AES_256
{
"Plaintext": "+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA=",
"KeyId": "arn:aws:kms:us-west-2:040512153658:key/64a62e3e-7e38-4f86-8ef2-3d00929e6260",
"CiphertextBlob": "AQIDAHgrvfqfgn9D0tTUJOISzFCz7ejMPZ6/HGX0kGAlzKYZ7wEiyHdpuGaOjpq4UQazPAgeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMU5JtbI6lxLOv/p4KAgEQgDsX97Pk+ywqLU2VymLRgDSz0exOyzRgLMgd7WEf3sLUh4GnbYllIrxNSdK/DSZrYUhBo78KYugnkTj89g=="
}
I then verify it by decrypting from the CLI:
$ aws kms decrypt --ciphertext-blob fileb://<(echo 'AQIDAHgrvfqfgn9D0tTUJOISzFCz7ejMPZ6/HGX0kGAlzKYZ7wEiyHdpuGaOjpq4UQazPAgeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMU5JtbI6lxLOv/p4KAgEQgDsX97Pk+ywqLU2VymLRgDSz0exOyzRgLMgd7WEf3sLUh4GnbYllIrxNSdK/DSZrYUhBo78KYugnkTj89g==' | base64 -d) --query Plaintext
"+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA="
Lo and behold! I get the Plaintext value back all nice and clean. I then try to grind that same ciphertext blob through the SDK using Java with the following code:
.
.
.
final String encryptedCipherText = "AQIDAHgrvfqfgn9D0tTUJOISzFCz7ejMPZ6/HGX0kGAlzKYZ7wEiyHdpuGaOjpq4UQazPAgeAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMU5JtbI6lxLOv/p4KAgEQgDsX97Pk+ywqLU2VymLRgDSz0exOyzRgLMgd7WEf3sLUh4GnbYllIrxNSdK/DSZrYUhBo78KYugnkTj89g==";
final String expectedPlainText = "+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA=";
AWSKMS kmsClient;
String returnValue;
kmsClient = AWSKMSClientBuilder
.standard()
.withRegion("us-west-2")
.build();
ByteBuffer cipherTextBlob = ByteBuffer.wrap(Base64.getDecoder().decode(encryptedCipherText));
DecryptRequest decryptRequest = new DecryptRequest().withCiphertextBlob(cipherTextBlob);
ByteBuffer key = kmsClient.decrypt(decryptRequest).getPlaintext();
final byte[] bytes = new byte[key.remaining()];
key.duplicate().get(bytes);
String result = new String(bytes);
if (expectedPlainText.equals(result)) {
LOG.info("decrypted plaintext matches expected");
} else {
LOG.error("decrypted plaintext unexpected value: " + result);
}
.
.
.
And the LOG entry dumped out was:
23:08:33.210 [main] ERROR com.eyefinity.magicmissile.aws.AwsClientConfig - decrypted plaintext unexpected value: �(�k�2!9�5��64=���3o6q�-��
I've tried encoding the result with every Charset available to me, and no Charset produces my original Plaintext key. As near as I can tell from all the examples I've seen, my code is correct. So what am I doing wrong or what am I missing here? All I want is to end up with a Java String variable that contains "+SjeaxtD5TIhOcY16+A2NA493MbxnYozbzZx4i3/BfA=".
I stumbled on my own solution: I was SO CLOSE! All that's required in the code above to extract the same Plaintext value that is returned from KMS, and the ASCII string I received on the aws-cli command line when generating the datakey, is to take the byte array and Base64 encode it. So referencing my sample code above, all the way at the top, replace the line that reads...
String result = new String(bytes);
with something like this:
String result = Base64.getEncoder().encodeToString(bytes);
So I am not the Crypto wizard by any means but here is some code I have that works in C# but does not return the same b64 string in Java.
c#
string _Cert = "long b64 string here";
string _Pass = "my password";
string lvreturn = "Test";
byte[] lvCertBytes = Convert.FromBase64String(_Cert);
X509Certificate2 lvCertFromBytes = new X509Certificate2(lvCertBytes, _Pass);
SHA1Managed lvSHA1 = new SHA1Managed();
byte[] lvData = Encoding.Unicode.GetBytes(lvReturn);
byte[] lvHash = lvSHA1.ComputeHash(lvData);
RSACryptoServiceProvider lvCryptoProvider = (RSACryptoServiceProvider)lvCertFromBytes.PrivateKey;
byte[] lvSignedBytes = lvCryptoProvider.SignHash(lvHash, CryptoConfig.MapNameToOID("SHA1"));
string lvToken = Convert.ToBase64String(lvSignedBytes);
Java
String certB64 = "long b64 string here";
char[] Pass = "text password".toCharArray();
String alias = "guid looking ID here";
String plaintext = "Test";
byte[] certbytes = Base64.getDecoder().decode(certB64);
InputStream in = new ByteArrayInputStream(certbytes);
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(in,Pass);
KeyStore.PrivateKeyEntry pvk = (KeyStore.PrivateKeyEntry)keystore.getEntry(alias, new KeyStore.PasswordProtection(Pass));
PrivateKey pkey = (PrivateKey)pvk.getPrivateKey();
Signature rsa = Signature.getInstance("SHA1withRSA");
rsa.initSign(pkey);
rsa.update(plaintext.getBytes());
System.out.println("Hash: " + Base64.getEncoder().encodeToString(rsa.sign()));
I have Cert.pfx file that I want to use to use the privatekey to encrypt a https auth segment. I am just ripping the file to a base64 string and stuffing it into the "_Cert" var in C#. I do the same in Java. I want to sign the plaintext message using the private key of the cert and SHA1. The C# code below works and the https server provides a response. Java however is not spitting out the same base64 encoded string. Thanks for some help!
Update: I found a link to another post that is the same as mine but with a couple small diffs, and I didn't want to necro post on it. I followed it exactly removing the messagedigest piece of my original code. I tried reading directly from the pfx file or using the b64 string directly in the code. I am still not getting the same between Java and C#. At this point it has to be something small I am missing with encoding in Java because the C# is basically identical to mine.
Java Digital Signature different to C#