Class VAPIDKeys
- Author:
- Christopher Mindus
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intThe length in characters of a key fingerprint,fingerprint(String): 32 bytes of SHA-256 in base64url without padding.static final intThe length in bytes of a P-256 private scalar.static final intThe length in bytes of an uncompressed P-256 public point: the 0x04 tag plus the 32-byte X and Y coordinates.Constructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionstatic Stringfingerprint(String publicKey) Gets the fingerprint of a VAPID public key: the base64url encoding, without padding, of the SHA-256 of the 65-byte uncompressed point, 43 characters (PUSH-CLUSTER-DESIGN.mdsection 1).static String[]Generates a public key and a private key.static StringvalidatePrivateKey(String privateKey) Validates the private key Base64 encoded string.static StringvalidatePublicKey(String publicKey) Validates the public key Base64 encoded string.
Field Details
PUBLIC_KEY_LENGTH
public static final int PUBLIC_KEY_LENGTHThe length in bytes of an uncompressed P-256 public point: the 0x04 tag plus the 32-byte X and Y coordinates.- See Also:
PRIVATE_KEY_LENGTH
public static final int PRIVATE_KEY_LENGTHThe length in bytes of a P-256 private scalar.- See Also:
FINGERPRINT_LENGTH
public static final int FINGERPRINT_LENGTHThe length in characters of a key fingerprint,fingerprint(String): 32 bytes of SHA-256 in base64url without padding.- See Also:
Constructor Details
VAPIDKeys
public VAPIDKeys()
Method Details
generateKeys
Generates a public key and a private key.The keys are the RAW forms that Web Push requires, base64url encoded without padding: the public key is the uncompressed P-256 point,
0x04 || X || Y, 65 bytes; the private key is the unsigned scalard, 32 bytes, left-padded so its length never varies with the value.These are the forms
Utils.loadPublicKey(String)andUtils.loadPrivateKey(String)parse, and the public key is passed unchanged to the browser'spushManager.subscribeasapplicationServerKey.Until r19738 this method encoded
getEncoded()on both keys instead - X.509 SubjectPublicKeyInfo DER for the public key, 91 bytes, and PKCS#8 DER for the private. Neither is usable:loadPublicKeycallscurve.decodePointand threw on the DER, so the Designer's "Generate new VAPID Key Pair" produced keys that this class's own validators rejected and that no browser would accept. The private key was worse than a rejection -BigIntegers.fromUnsignedByteArrayread the whole DER blob as the scalar and returned a wrong key without complaint.- Returns:
- Array of 2 String's: first the public key, then the private key.
- Throws:
IllegalStateException- NOTE: try-catch on it! In case of BouncyCastle errors.
validatePublicKey
Validates the public key Base64 encoded string.Accepted is the base64url form of an uncompressed P-256 point,
0x04 || X || Y, 65 bytes, whose coordinates lie in the field and satisfy the curve equationy^2 = x^3 + ax + b (mod p). The equation is evaluated here, because the JDK'sKeyFactorybuilds a public key from any pair of coordinates without checking it - see the comment in the body. A key that passes here is one the push service will verify a VAPID signature against.- Parameters:
publicKey- The public key to validate.- Returns:
- A validation message, or
nullfor success.
validatePrivateKey
Validates the private key Base64 encoded string.Accepted is the base64url form of the P-256 private scalar
d, exactly 32 bytes, whose value lies in[1, n-1]for the ordernof the curve. The range is checked here, because the JDK'sKeyFactorybuilds a private key from any scalar without checking it - see the comment in the body. A key that passes here is one the transports can sign with.- Parameters:
privateKey- The private key to validate.- Returns:
- A validation message, or
nullfor success.
fingerprint
Gets the fingerprint of a VAPID public key: the base64url encoding, without padding, of the SHA-256 of the 65-byte uncompressed point, 43 characters (PUSH-CLUSTER-DESIGN.mdsection 1). A subscription row records it as the key the subscription was made under (IZS.SUBSCRIPTIONS.vapid_key, B-10a).A public key is not a secret, and neither is its fingerprint: it is used because it is fixed-length and cheap to compare, not to hide anything. Only the encoding is checked here, not the curve -
validatePublicKey(String)does that: the same point gives the same fingerprint whether its base64url text carries padding or not, and text that is not the base64url form of a 65-byte uncompressed point gives none.- Parameters:
publicKey- The public key, base64url, may be null.- Returns:
- The fingerprint, or null when
publicKeyis null or not the base64url form of a 65-byte uncompressed point.