Elliptic Curve Digital Signature Algorithm (ECDSA) is a digital signature algorithm (DSA) commonly used for digital signatures. This article will introduce how to use ECDSA to sign and verify in Android and iOS.
The complete Android code for this chapter can be found in .
The complete iOS code for this chapter can be found in .
Table of Contents
Digital Signature
Sometimes we need to verify whether the data received from the server is really sent by the server, or if someone else pretends to be the server and sends the data to us. In order to solve this problem, the server will send an additional verification code when sending data. When the client receives the data and verification code, the client will use a specific algorithm to convert the data into a string, and then compare the string with the verification code. If they are the same, we can be sure that the data is sent by the server and claim the data is safe.
Digital signature basically defines the above process and provides a reliable algorithm to prevent others from forging verification codes. The process of generating verification codes on the server side is called signing. First, the server must first process the data with a specific hash function, which will produce a relatively short and fixed-length hash value. Then, this hash value and a private key are input into a specific DSA, and finally it will generate a string of verification codes, called a signature.
The client receives the data and signature passed from the server. It processes the data with a specific hash function and obtains a hash value. Enter the signature and a public key into a specific DSA and it will generate a hash value. Finally, compare the two hash values to see if they are the same. This process is called verifying.
ECDSA Signature
ECDSA is a DSA commonly used in recent years. When using ECDSA, the server and client should agree on the same curve parameters. In the example of this article, we choose secp256r1. SEC secp256r1, NIST P-256, and ANSI X9.64 ansix9p256r1 are all the same. It’s just that they are defined by different agencies, please refer to here.
When choosing to use ECDSA and secp256r1, the signing process will be as follows:
However, the verification process is as follows:
Example in Kotllin
ECC Keys Generation
import android.util.Base64 import java.security.KeyPairGenerator import java.security.interfaces.ECPrivateKey import java.security.interfaces.ECPublicKey import java.security.spec.ECGenParameterSpec var privateKeyBase64 = "" var publicKeyBase64 = "" var message = "Hello Wayne's Talk!" var signatureBase64 = "" fun generateKeys() { val keyPairGenerator = KeyPairGenerator.getInstance("EC") val ecGenParameterSpec = ECGenParameterSpec("secp256r1") keyPairGenerator.initialize(ecGenParameterSpec) val keyPair = keyPairGenerator.generateKeyPair() val privateKey = keyPair.private as ECPrivateKey val publicKey = keyPair.public as ECPublicKey privateKeyBase64 = Base64.encodeToString(privateKey.encoded, Base64.NO_WRAP) publicKeyBase64 = Base64.encodeToString(publicKey.encoded, Base64.NO_WRAP) println("Private Key: $privateKeyBase64") println("Private Key Format: ${privateKey.format}") println("Public Key: $publicKeyBase64") println("Public Key Format: ${publicKey.format}") }
Signing
import android.util.Base64 import java.security.KeyFactory import java.security.Signature import java.security.spec.PKCS8EncodedKeySpec fun sign() { val privateKeyBytes = Base64.decode(privateKeyBase64, Base64.NO_WRAP); val pkcS8EncodedKeySpec = PKCS8EncodedKeySpec(privateKeyBytes) val keyFactory = KeyFactory.getInstance("EC") val privateKey = keyFactory.generatePrivate(pkcS8EncodedKeySpec) val signature = Signature.getInstance("SHA256withECDSA") signature.initSign(privateKey) signature.update(message.encodeToByteArray()) val signatureBytes = signature.sign() signatureBase64 = Base64.encodeToString(signatureBytes, Base64.NO_WRAP) println("Message: $message") println("Signature: $signatureBase64") }
Verifying
import android.util.Base64 import java.security.KeyFactory import java.security.Signature import java.security.spec.X509EncodedKeySpec fun verify() { val publicKeyBytes = Base64.decode(publicKeyBase64, Base64.NO_WRAP) val x509EncodedKeySpec = X509EncodedKeySpec(publicKeyBytes) val keyFactory = KeyFactory.getInstance("EC") val publicKey = keyFactory.generatePublic(x509EncodedKeySpec) val signature = Signature.getInstance("SHA256withECDSA") signature.initVerify(publicKey) signature.update(message.encodeToByteArray()) val signatureBytes = Base64.decode(signatureBase64, Base64.NO_WRAP) val isValid = signature.verify(signatureBytes) println("Signature is ${if (isValid) "valid" else "inValid"}") }
Example in Swift
ECC Keys Generation
import CryptoKit private var privateKeyBase64 = "" private var publicKeyBase64 = "" private var signagureBase64 = "" private let message = "Hello Wayne's Talk!" func generateKeys() { let privateKey = P256.Signing.PrivateKey() let publicKey = privateKey.publicKey privateKeyBase64 = privateKey.derRepresentation.base64EncodedString() publicKeyBase64 = publicKey.derRepresentation.base64EncodedString() print("Private Key: (privateKeyBase64)") print("Public Key: (publicKeyBase64)") }
Signing
func sign() { let privateKeyData = Data(base64Encoded: privateKeyBase64)! let privateKey = try! P256.Signing.PrivateKey(derRepresentation: privateKeyData) let signature = try! privateKey.signature(for: message.data(using: .utf8)!) signatureBase64 = signature.derRepresentation.base64EncodedString() print("Signature: (signatureBase64)") }
Verifying
func verify() { let publicKeyData = Data(base64Encoded: publicKeyBase64)! let publicKey = try! P256.Signing.PublicKey(derRepresentation: publicKeyData) var sha256 = SHA256() sha256.update(data: message.data(using: .utf8)!) let messageData = sha256.finalize() let signatureData = Data(base64Encoded: signatureBase64)! let signature = try! P256.Signing.ECDSASignature(derRepresentation: signatureData) let isValid = publicKey.isValidSignature(signature, for: messageData) print("Signature is (isValid ? "valid" : "invalid")") }
Conclusion
Under the same key length, ECDSA provides a higher security level than RSA. The use of ECDSA has increased significantly in recent years. Android and iOS do not have all curve parameters built-in. Therefore, when selecting curve parameters, you must first confirm whether the device has built-in curve parameters. Otherwise, it is better to use a third-party package to be safer.