diff --git a/docs/wallet/06-encryption-architecture.md b/docs/wallet/06-encryption-architecture.md index 6e0cdc3..c1f996a 100644 --- a/docs/wallet/06-encryption-architecture.md +++ b/docs/wallet/06-encryption-architecture.md @@ -3,7 +3,19 @@ # Encryption Architecture -## Changes from v1 +## Changes from v2 to v3 + +- Introduced asymmetric (ECDH-ES) wrapping layer between + **prfKey**/**passwordKey** and **mainKey**. This enables **mainKey** to be + easily rotated as the new key can be re-encrypted under the public key of each + **prfKey** and **passwordKey**, instead of requiring each **prfKey** and + **passwordKey** to be available to re-wrap the new **mainKey**. + +- **privateKey** now labeled in diagram as "ECDSA secp256r1" instead of "EC + secp256r1". + + +## Changes from v1 to v2 - Deleted **outerSessionKey**. **innerSessionKey** is renamed to **sessionKey** and is now stored in plaintext in session storage alongside the @@ -16,15 +28,14 @@ signed in to the same account, and to sign out of existing tabs if any tab signs out or signs in to a different account. -## Encryption Architecture v2 +## Encryption Architecture v3 wwWallet uses the [WebAuthn `prf` extension](https://w3c.github.io/webauthn/#prf-extension) to derive encryption keys for the wallet contents, including the user's private proof signing key. This document explains the encryption architecture and its design rationale, as well as providing critique of the same. - -![Diagram: Wallet encryption architecture](../../static/img/diagrams/wallet-encryption-architecture-v2.svg) +[![Diagram: Wallet encryption architecture](../../static/img/diagrams/wallet-encryption-architecture-v3.svg)](../../static/img/diagrams/wallet-encryption-architecture-v3.svg) The wallet uses the following keys and data types, as labeled in the above diagram: @@ -38,6 +49,33 @@ The wallet uses the following keys and data types, as labeled in the above diagr including the user's DID and public proof signing key. All of these contents are encrypted at rest on both the server side and the client side. +- `EphemeralEncapsulationInfo`: An ephemeral ECDH public key and auxiliary + parameters to use for unwrapping the **mainKey** used to encrypt the + `EncryptedContainer`. This is shared between all **prfKey**s and + **passwordKey**s in the `EncryptedContainer`. + +- `StaticEncapsulationInfo`: A wrapped copy of the **mainKey** along with a + static ECDH key pair **wrapPublicKey** and **wrapPrivateKey**. This is unique + per **prfKey** and **passwordKey**. The ECDH private key is in turn wrapped by + the associated **prfKey** or **passwordKey**. + + When creating a new **mainKey**, a new **ephPublicKey** and **ephPrivateKey** + pair is created and each `StaticEncapsulationInfo` is updated as follows. An + ECDH exchange is made between **ephPrivateKey** and the **wrapPublicKey** of + the `StaticEncapsulationInfo`. The resulting **wrappingKey** is used to wrap + the new **mainKey**, and the resulting wrapping is stored in the + `StaticEncapsulationInfo`. Finally, the **ephPublicKey** is stored in the + `EphemeralEncapsulationInfo` of the `EncryptedContainer` and the + **ephPrivateKey** is discarded. + + During sign-in, the user chooses a **prfKey** or **passwordKey** which is used + to unwrap the **wrapPrivateKey** stored in the associated + `StaticEncapsulationInfo`. The opposite ECDH exchange is made between + **wrapPrivateKey** and the stored **ephPublicKey** to derive the + **wrappingKey** used to unwrap the **mainKey** stored in the + `StaticEncapsulationInfo`, and finally **mainKey** is used to decrypt the + `EncryptedContainer`. + - **privateKey**: The user's proof signing secp256r1 private key. This is the long-lived key that is used to prove the user's ownership of the wallet. This key is generated once, as part of creating the user's wallet when they first @@ -51,50 +89,71 @@ The wallet uses the following keys and data types, as labeled in the above diagr - **mainKey**: The 256-bit AES-GCM encryption key of the `EncryptedContainer`. This is used to decrypt the contained `PrivateData` and is itself stored in - encrypted (wrapped) form in the `EncryptedContainer`, encrypted using each of - the user's **prfKey**s and, if applicable, **passwordKey**. + encrypted (wrapped) form in the `EncryptedContainer`, asymmetrically encrypted + using each of the user's **prfKey**s and, if applicable, **passwordKey**. - This key is generated once, as part of creating the user's wallet when they - first create a wwWallet account. + This key is generated as part of creating the user's wallet when they first + create a wwWallet account, but may be replaced at any time. **mainKey** is only kept in volatile memory, and is never written to persistent storage in unencrypted form. -- **prfKey**: An 256-bit AES-KW key-wrapping key derived using the WebAuthn - `prf` extension. This is used to unwrap the **mainKey** in order to decrypt - the `EncryptedContainer` contents during sign-in. +- **prfKey**: A 256-bit AES-GCM encryption key derived using the WebAuthn `prf` + extension. This is used to wrap and unwrap an associated + `StaticEncapsulationInfo` structure in order to decrypt the + `EncryptedContainer` contents during sign-in. The user may have 0 or more instances of **prfKey** (or at least 1, when password authentication is disabled), each corresponding to a WebAuthn - credential the user may use to sign in to the backend service. + credential the user may use to sign in to the backend service. Each **prfKey** + has its own unique associated `StaticEncapsulationInfo`. The **prfSalt** and HKDF parameters used to derive **prfKey** are randomly generated once, when the corresponding WebAuthn credential is registered. **prfKey** is only kept in volatile memory, and is never written to persistent - storage in unencrypted form. + storage. -- **passwordKey**: A 256-bit AES-KW key-wrapping key derived from a password +- **passwordKey**: A 256-bit AES-GCM encryption key derived from a password using PBKDF2. This is a legacy feature that is usually disabled. Like - **prfKey**, this is used to unwrap the **mainKey** in order to decrypt the - `EncryptedContainer` contents during sign-in. + **prfKey**, this is used to wrap and unwrap an associated + `StaticEncapsulationInfo` structure in order to decrypt the + `EncryptedContainer` contents during sign-in. The **passwordKey** has its own + unique associated `StaticEncapsulationInfo`. The PBKDF2 salt used to derive **passwordKey** is randomly generated once, when the account is created. Changing the password is not possible as of this writing. **passwordKey** is only kept in volatile memory, and is never written to - persistent storage in unencrypted form. + persistent storage. + +- **wrapPrivateKey** and **wrapPublicKey**: The static ECDH keypair of a + `StaticEncapsulationInfo`. These are used to perform an ECDH exchange with the + **ephPublicKey** or **ephPrivateKey**, respectively, to derive the + **wrappingKey** used to decrypt or encrypt the **mainKey**. + + Each **wrapPrivateKey** is only kept in volatile memory, and is never written + to persistent storage in unencrypted form. Each **wrapPublicKey** is stored in + cleartext in the `StaticEncapsulationInfo`. + +- **ephPrivateKey** and **ephPublicKey**: An ephemeral ECDH keypair for wrapping + the **mainKey**. These are used to perform an ECDH exchange with a + **wrapPublicKey** or **wrapPrivateKey**, respectively, to derive the + **wrappingKey** used to decrypt or encrypt the **mainKey**. + + **ephPublicKey** is stored as an `EphemeralEncapsulationInfo` structure in the + `EncryptedContainer`. **ephPrivateKey** is only kept in volatile memory, and + is discarded after wrapping the **mainKey**. - **sessionKey**: A 256-bit AES-GCM encryption key used to decrypt the `EncryptedContainer` for the duration of a session. - Upon successful sign-in, the user's **prfKey** or **passwordKey** is used to - unwrap **mainKey** which in turn decrypts the `EncryptedContainer` to access - the cleartext `PrivateData`. The `PrivateData` is then re-encrypted using a + Upon successful sign-in, the `EncryptedContainer` is first decrypted using + **mainKey** as described above. The `PrivateData` is then re-encrypted using a newly generated **sessionKey**, resulting in the ciphertext `privateDataJwe` which is stored in the client's [session storage][sessionStorage]. The - **sessionKey** is also stored in session storage alongside the + **sessionKey** is also stored in cleartext session storage alongside the `privateDataJwe`. @@ -108,12 +167,13 @@ keys by the following rationale. ### Re-encrypting wallet contents to a session key -Since we keep the wallet contents encrypted at rest, we need to decrypt it -whenever we need to access the contents. This would require handling the -**mainKey** for decryption, but the **mainKey** is a long-lived key that is not -easily replaceable (see below). Therefore we use the **mainKey** to decrypt the -contents only once, and then use temporary encryption key for the remainder of -the session. This way we minimize the exposure of the **mainKey**. +This is a vestigial feature from the v1 and v2 architecture iterations where +**mainKey** was a long-lived key that was not easily replaceable. The +**sessionKey** was therefore used to minimize the exposure of the **mainKey**. + +This v3 architecture revision allows for frequently rotating the **mainKey**, +but we keep the **sessionKey** for now since rotation of **mainKey** is not yet +implemented. ### Selection of client-side storage areas @@ -166,6 +226,14 @@ we encrypt it an additional time so that we can access the other members of `PrivateData` without exposing **privateKey** in cleartext unnecessarily. +### Using **prfKey** and **passwordKey** to wrap en ECDH private key + +The [`deriveKey()`][derive-key] function in WebCrypto does not support deriving +an ECDH private key deterministically, for example from PRF output or from an +PBKDF2 output key. Therefore we instead have to generate the ECDH key pair +nondeterministically and store the wrapped private key. + + ## Critique This design has some drawbacks, and some of the intended advantages are @@ -173,21 +241,13 @@ debatable. The following critique may inform a revised design. This is not exhaustive; we invite additional and ongoing review and critique of the design. -### Rotating the main encryption key - -The **mainKey** cannot easily be replaced since that would require access to -each **prfKey** and **passwordKey** in order to update each corresponding key -wrapping. This could be solved by having each **prfKey** and **passwordKey** -wrap an ECDH private key instead of wrapping the **mainKey** directly, and -instead using ECDH to derive the wrapping key for the main key. - - ### Cleartext session key The **sessionKey** is used for user convenience: once logged in, the session key can be used for the duration of the session to access encrypted data. However, -this might not improve security much; it may not be materially less secure to -simply store the **mainKey** itself in cleartext in session storage. +this might not improve security much; with **mainKey** now easily replaceable it +is not materially less secure to simply store the **mainKey** itself in +cleartext in session storage. ### Weak encryption at rest @@ -257,6 +317,7 @@ arbitrary data with a hardware-bound private key. [cryptokey]: https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey +[derive-key]: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveKey [localStorage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage [sessionStorage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage [webcrypto]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API diff --git a/docs/wallet/07-encryption-architecture/01-v2.md b/docs/wallet/07-encryption-architecture/01-v2.md new file mode 100644 index 0000000..5dc6ace --- /dev/null +++ b/docs/wallet/07-encryption-architecture/01-v2.md @@ -0,0 +1,262 @@ +--- +--- + +# Encryption Architecture v2 + +## Changes from v1 + +- Deleted **outerSessionKey**. **innerSessionKey** is renamed to **sessionKey** + and is now stored in plaintext in session storage alongside the + `privateDataJwe` which it encrypts. + +- Moved cache of WebAuthn RP ID and user handle from local storage to session storage. + +These changes were made in order to support using the app in multiple tabs +signed in to the same account, and to sign out of existing tabs if any tab signs +out or signs in to a different account. + + +## Encryption Architecture v2 + +wwWallet uses the [WebAuthn `prf` extension](https://w3c.github.io/webauthn/#prf-extension) +to derive encryption keys for the wallet contents, including the user's private +proof signing key. This document explains the encryption architecture and its +design rationale, as well as providing critique of the same. + + +![Diagram: Wallet encryption architecture](../../../static/img/diagrams/wallet-encryption-architecture-v2.svg) + + +The wallet uses the following keys and data types, as labeled in the above diagram: + +- `EncryptedContainer`: The user's wallet contents in encrypted form. This is + stored both in the backend server database, and downloaded to the client's + [local storage][localStorage] when the user signs in to the wallet. + +- `PrivateData`: The cleartext contents of an `EncryptedContainer`. This + contains both sensitive data, namely **privateKey**, and non-sensitive data, + including the user's DID and public proof signing key. All of these contents + are encrypted at rest on both the server side and the client side. + +- **privateKey**: The user's proof signing secp256r1 private key. This is the + long-lived key that is used to prove the user's ownership of the wallet. This + key is generated once, as part of creating the user's wallet when they first + create a wwWallet account. + + The **privateKey** member of `PrivateData` is encrypted an additional time + using the same encryption key. + + **privateKey** is only kept in volatile memory, and is never written to + persistent storage in unencrypted form. + +- **mainKey**: The 256-bit AES-GCM encryption key of the `EncryptedContainer`. + This is used to decrypt the contained `PrivateData` and is itself stored in + encrypted (wrapped) form in the `EncryptedContainer`, encrypted using each of + the user's **prfKey**s and, if applicable, **passwordKey**. + + This key is generated once, as part of creating the user's wallet when they + first create a wwWallet account. + + **mainKey** is only kept in volatile memory, and is never written to + persistent storage in unencrypted form. + +- **prfKey**: An 256-bit AES-KW key-wrapping key derived using the WebAuthn + `prf` extension. This is used to unwrap the **mainKey** in order to decrypt + the `EncryptedContainer` contents during sign-in. + + The user may have 0 or more instances of **prfKey** (or at least 1, when + password authentication is disabled), each corresponding to a WebAuthn + credential the user may use to sign in to the backend service. + + The **prfSalt** and HKDF parameters used to derive **prfKey** are randomly + generated once, when the corresponding WebAuthn credential is registered. + + **prfKey** is only kept in volatile memory, and is never written to persistent + storage in unencrypted form. + +- **passwordKey**: A 256-bit AES-KW key-wrapping key derived from a password + using PBKDF2. This is a legacy feature that is usually disabled. Like + **prfKey**, this is used to unwrap the **mainKey** in order to decrypt the + `EncryptedContainer` contents during sign-in. + + The PBKDF2 salt used to derive **passwordKey** is randomly generated once, + when the account is created. Changing the password is not possible as of this + writing. + + **passwordKey** is only kept in volatile memory, and is never written to + persistent storage in unencrypted form. + +- **sessionKey**: A 256-bit AES-GCM encryption key used to decrypt the + `EncryptedContainer` for the duration of a session. + + Upon successful sign-in, the user's **prfKey** or **passwordKey** is used to + unwrap **mainKey** which in turn decrypts the `EncryptedContainer` to access + the cleartext `PrivateData`. The `PrivateData` is then re-encrypted using a + newly generated **sessionKey**, resulting in the ciphertext `privateDataJwe` + which is stored in the client's [session storage][sessionStorage]. The + **sessionKey** is also stored in session storage alongside the + `privateDataJwe`. + + +## Design rationale + +The primary concerns during the development of this design was to keep all key +material on the client side, and to minimize the exposure of long-lived secrets. +Thus we keep the wallet contents encrypted at rest, and introduced the session +keys by the following rationale. + + +### Re-encrypting wallet contents to a session key + +Since we keep the wallet contents encrypted at rest, we need to decrypt it +whenever we need to access the contents. This would require handling the +**mainKey** for decryption, but the **mainKey** is a long-lived key that is not +easily replaceable (see below). Therefore we use the **mainKey** to decrypt the +contents only once, and then use temporary encryption key for the remainder of +the session. This way we minimize the exposure of the **mainKey**. + + +### Selection of client-side storage areas + +We use the [Web Crypto API][webcrypto] for encryption, decryption and key +management operations. The `CryptoKey` objects do not survive page reload or +top-level navigation unless stored in some persistent storage. We use two +client-side storage areas: [local storage][localStorage] and [session +storage][sessionStorage]. + +#### Local storage + +We store the `EncryptedContainer` in [local storage][localStorage] in +anticipation of the possibility to use the wallet in offline mode in the future. +We also cache some other parameters: + +- The **prfKey** derivation parameters for each user that has logged in on the + machine, and a display name for the user. These are used to eliminate the need + for the user to authenticate twice to sign in to the wallet: once to retrieve + the `EncryptedContainer`, including the PRF salts used to derive a **prfKey**, + and once to evaluate the PRF with the retrieved salt. The cached salt allows + both of these steps to be performed in a single WebAuthn authentication + ceremony. The user may delete any entry of this cache while logged out. + +- The user's WebAuthn user handle, needed to detect if the user signs in to a + different account in a different browser tab and log out of the older tab in + that case. + + +#### Session storage + +We store the **sessionKey** and re-encrypted `privateDataJwe` in [session +storage][sessionStorage] so that they expire when the user closes the browser +tab. We also cache some other parameters: + +- The WebAuthn RP ID for the wwWallet service, needed to derive **prfKey**s. + This could be a configuration constant of the frontend app, but the backend + already sends it during the initial authentication or signup, so we cache the + value and eliminate the possibility of config mismatch. + +- The user's WebAuthn user handle, needed to detect if the user signs in to a + different account in a different browser tab and log out of the older tab in + that case. + + +### Encrypting **privateKey** twice + +Since **privateKey** is more sensitive than other members of `PrivateData`, +we encrypt it an additional time so that we can access the other members of +`PrivateData` without exposing **privateKey** in cleartext unnecessarily. + + +## Critique + +This design has some drawbacks, and some of the intended advantages are +debatable. The following critique may inform a revised design. This is not +exhaustive; we invite additional and ongoing review and critique of the design. + + +### Rotating the main encryption key + +The **mainKey** cannot easily be replaced since that would require access to +each **prfKey** and **passwordKey** in order to update each corresponding key +wrapping. This could be solved by having each **prfKey** and **passwordKey** +wrap an ECDH private key instead of wrapping the **mainKey** directly, and +instead using ECDH to derive the wrapping key for the main key. + + +### Cleartext session key + +The **sessionKey** is used for user convenience: once logged in, the session key +can be used for the duration of the session to access encrypted data. However, +this might not improve security much; it may not be materially less secure to +simply store the **mainKey** itself in cleartext in session storage. + + +### Weak encryption at rest + +Although the `EncryptedContainer` itself is stored in encrypted form, we also +store all encryption keys needed to decrypt it. This means that the encryption +at rest is at best a "security by obscurity" measure or, more charitably, a +dubious form of "defense in depth". It would thus be preferable to retrieve or +derive the encryption keys from data not stored in cleartext on the client +device. + +The session keys could be eliminated in favour of simply re-deriving the +**prfKey** or **passwordKey** whenever sensitive contents need to be accessed. +This would require the user to perform an authentication ceremony (presenting a +WebAuthn credential or entering a password) for each access. This may or may not +be an acceptable user experience. The keys could be kept in application memory +for a short time to avoid bursts of multiple authentication prompts during a +single semantic user action. In fact the app already does this when adding or +deleting WebAuthn credentials, which each need a corresponding **prfKey**. + + +### Encrypting **privateKey** twice + +Likewise, encrypting **privateKey** twice may not materially improve security +either. An adversary with read access to the other `PrivateData` members will +likely also have read access to both of local storage and session storage, thus +having access to the keys needed to decrypt **privateKey** anyway. + + +### **passwordKey** is not entirely client-side + +When a **passwordKey** is used, the key material and algorithm parameters needed +to derive **passwordKey** are exposed to the backend service. To make +**passwordKey** entirely client-side, making it impossible for the backend +service to access the contents of the `EncryptedContainer`, a different +passphrase should be used to derive **passwordKey** than is used to sign in to +the backend service. Alternatively, some password blinding method such as a +[PAKE](https://en.wikipedia.org/wiki/Password-authenticated_key_agreement) +protocol might be used to keep the backend server from learning the user's +password. + + +### Software keys, not hardware keys + +All cryptographic keys used by wwWallet are fundamentally software keys, held in +browser memory. This is due to technical limitations, some of which may change +in the future. + +However, note the difference between encryption keys and signing keys. +Encryption and decryption inherently involves exposing the cleartext anyway, so +encryption keys do not need to be kept secret from parties accessing the +cleartext. + +The WebAuthn `prf` extension simply returns pseudo-random data which wwWallet +uses to derive encryption keys. Thus the encryption keys are software keys held +by the browser, but the WebAuthn authenticator holding the PRF key is needed in +order to access the PRF outputs. This is sufficient hardware binding for +encryption keys, assuming the browser is benevolent. + +Ideally the user's **privateKey** should be a hardware-bound key, so that even +if the **mainKey** or the `PrivateData` is exposed, an unauthorized party would +still not be able to sign proofs on behalf of the legitimate user. This is not +currently possible due to technical limitations. Although WebAuthn +authentication keys may be hardware-bound, they do not support signing arbitrary +data. Future extensions to the WebAuthn API might add the possibility to sign +arbitrary data with a hardware-bound private key. + + +[cryptokey]: https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey +[localStorage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage +[sessionStorage]: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage +[webcrypto]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API diff --git a/docs/wallet/07-encryption-architecture/01-v1.md b/docs/wallet/07-encryption-architecture/02-v1.md similarity index 99% rename from docs/wallet/07-encryption-architecture/01-v1.md rename to docs/wallet/07-encryption-architecture/02-v1.md index ba06249..5e854f4 100644 --- a/docs/wallet/07-encryption-architecture/01-v1.md +++ b/docs/wallet/07-encryption-architecture/02-v1.md @@ -8,7 +8,7 @@ to derive encryption keys for the wallet contents, including the user's private proof signing key. This document explains the encryption architecture and its design rationale, as well as providing critique of the same. -![Diagram: Wallet encryption architecture](../../../static/img/diagrams/wallet-encryption-architecture.svg) +![Diagram: Wallet encryption architecture](../../../static/img/diagrams/wallet-encryption-architecture-v1.svg) The wallet uses the following keys and data types, as labeled in the above diagram: diff --git a/static/img/diagrams/wallet-encryption-architecture-v3.svg b/static/img/diagrams/wallet-encryption-architecture-v3.svg new file mode 100644 index 0000000..d61e65e --- /dev/null +++ b/static/img/diagrams/wallet-encryption-architecture-v3.svg @@ -0,0 +1,4 @@ + + + +
Legend
PrfKeyInfo
+ mainKey: StaticEncapsulationInfo
+ credentialId: bytes
+ hkdfSalt: bytes
+ hkdfInfo: bytes
+ prfSalt: bytes
localStorage
«EncryptedContainer»
privateData
Backend database
«EncryptedContainer»
privateData
sessionStorage
privateDataJwe
Password
input
sessionKey
OKM
HKDF-SHA256
EncryptedContainer
+ prfKeys: PrfKeyInfo[]
+ passwordKey: PasswordKeyInfo
+ mainKey: EphemeralEncapsulationInfo
+ jwe: JWE
PasswordKeyInfo
+ mainKey: StaticEncapsulationInfo
+ pbkdf2Params: Pbkdf2Params
ciphertext
copy
WebAuthn

prf ext. output
prf ext.
input
IKM
wrappingKey
«CryptoKey»
prfKey
AES-GCM-256
wrapped
key
key
«CryptoKey»
mainKey
AES-GCM-256
ciphertext
AES-GCM
Generate key
copy
PrivateData
+ did: string
+ publicKey: JWK
+ privateKey: WrappedPrivateKeyInfo
WrappedPrivateKeyInfo
+ wrappedKey: bytes
+ aesGcmParams: AesGcmParams
+ unwrappedKeyAlgo: EcKeyImportParams
cleartext
AES-GCM
cleartext
AES-GCM
ciphertext
iv, aad, tagLength
cleartext
«CryptoKey»
privateKey
ECDSA secp256r1
OKM
PBKDF2
wrappingKey
«CryptoKey»
passwordKey
AES-GCM-256
hash, salt,
iterations
Generate key
store in cleartext
key
key
«CryptoKey»
sessionKey
AES-GCM-256
ciphertext
cleartext
AES-GCM
AES-GCM
ciphertext, iv,
aad, tagLength
User
Verification
User
CTAP2 authenticator
with hmac-secret extension
Password related
PRF related
Long lived
keys/data
Session keys/data
Generate key
Client side storage
Server side storage
PrivateData (reencrypted)
+ did: string
+ publicKey: JWK
+ privateKey: WrappedPrivateKeyInfo
StaticEncapsulationInfo
+ wrappedKey: bytes
+ publicKey: EcdhPublicKey
+ privateKey: EncapsulationPrivateKeyInfo
EncapsulationPrivateKeyInfo
+ unwrapAlgo: { name: "AES-GCM", iv: bytes }
+ unwrappedKeyAlgo: { "ECDH", "P-256" }
+ wrappedKey: bytes
ECDH private
«CryptoKey»
wrapPrivateKey
ECDHS secp256r1
Generate keypair
ECDH public
«CryptoKey»
wrapPublicKey
ECDHS secp256r1
ECDH private
«CryptoKey»
ephPrivateKey
ECDHE secp256r1
Generate keypair
ECDH public
«CryptoKey»
ephPublicKey
ECDHE secp256r1
«CryptoKey»
wrappingKey
AES-KW-256
shared key
ECDH
Ephemeral-Static
wrapped
AES-KW
ciphertext
wrappingKey
Persistent data
+ attribute: type
Short-lived
variables,
processes
Ephemeral keys
Semi-
ephemeral keys
EphemeralEncapsulationInfo
+ unwrapAlgo: "AES-KW"
+ unwrappedKeyAlgo: { "ECDH", "P-256" }
+ publicKey: EcdhPublicKey
\ No newline at end of file diff --git a/static/img/diagrams/wallet-encryption-architecture.svg b/static/img/diagrams/wallet-encryption-architecture.svg deleted file mode 100644 index 398fa5a..0000000 --- a/static/img/diagrams/wallet-encryption-architecture.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
localStorage
localStorage
«EncryptedContainer»
privateData
«EncryptedContainer»...
Backend database
Backend database
«EncryptedContainer»
privateData
«EncryptedContainer»...
sessionStorage
sessionStorage
indexedDB
indexedDB
privateDataJwe
privateDataJwe
Password
input
Password...
innerSessionKey
innerSessionKey
outerSessionKey
outerSessionKey
OKM
OKM
HKDF-SHA256
HKDF-SHA256
EncryptedContainer
EncryptedContainer
+ jwe: JWE
+ jwe: JWE
+ passwordKey: PasswordKeyInfo
+ passwordKey: PasswordKeyInfo
+ prfKeys: PrfKeyInfo[]
+ prfKeys: PrfKeyInfo[]
PrfKeyInfo
PrfKeyInfo
+ mainKey: WrappedKeyInfo
+ mainKey: WrappedKeyInfo
+ credentialId: bytes
+ credentialId: bytes
+ hkdfSalt: bytes
+ hkdfSalt: bytes
+ hkdfInfo: bytes
+ hkdfInfo: bytes
+ prfSalt: bytes
+ prfSalt: bytes
PasswordKeyInfo
PasswordKeyInfo
+ pbkdf2Params: Pbkdf2Params
+ pbkdf2Params: Pbkdf2Params
+ mainKey: WrappedKeyInfo
+ mainKey: WrappedKeyInfo
WrappedKeyInfo
WrappedKeyInfo
+ wrappedKey: bytes
+ wrappedKey: bytes
+ unwrapAlgo: "AES-KW"
+ unwrapAlgo: "AES-KW"
+ unwrappedKeyAlgo: AlgorithmIdentifier
+ unwrappedKeyAlgo: AlgorithmIdentifi...
ciphertext
ciphertext
copy
copy
WebAuthn
WebAuthn
prf
extension input
prf...
IKM
IKM
prf
extension output
prf...
PublicKeyCredential
PublicKeyCredential
wrappingKey
wrappingKey
«CryptoKey»
prfKey
AES-KW-256
«CryptoKey»...
salt
salt
info
info
wrapped
wrapped
key
key
key
key
wrapped
wrapped
«CryptoKey»
mainKey
AES-GCM-256
«CryptoKey»...
ciphertext
ciphertext
AES-KW
AES-KW
Generate key
Generate key
copy
copy
PrivateData
PrivateData
+ did: string
+ did: string
+ publicKey: JWK
+ publicKey: JWK
+ privateKey: WrappedPrivateKeyInfo
+ privateKey: WrappedPrivateKeyInfo
WrappedPrivateKeyInfo
WrappedPrivateKeyInfo
+ wrappedKey: bytes
+ wrappedKey: bytes
+ aesGcmParams: AesGcmParams
+ aesGcmParams: AesGcmParams
+ unwrappedKeyAlgo: EcKeyImportParams
+ unwrappedKeyAlgo: EcKeyImportParams
cleartext
cleartext
AES-GCM
AES-GCM
cleartext
cleartext
AES-GCM
AES-GCM
ciphertext
ciphertext
iv, aad, tagLength
iv, aad, tagLength
cleartext
cleartext
«CryptoKey»
privateKey
EC secp256r1
«CryptoKey»...
OKM
OKM
PBKDF2
PBKDF2
wrappingKey
wrappingKey
«CryptoKey»
passwordKey
AES-KW-256
«CryptoKey»...
hash, salt,
iterations
hash, salt,...
ciphertext
ciphertext
AES-KW
AES-KW
Generate key
Generate key
Generate key
Generate key
wrapped
wrapped
key
key
key
key
«CryptoKey»
innerSessionKey
AES-GCM-256
«CryptoKey»...
wrappingKey
wrappingKey
store in cleartext
store in cleartext
«CryptoKey»
outerSessionKey
AES-KW
«CryptoKey»...
ciphertext
ciphertext
AES-KW
AES-KW
ciphertext
ciphertext
cleartext
cleartext
AES-GCM
AES-GCM
AES-GCM
AES-GCM
ciphertext, iv,
aad, tagLength
ciphertext, iv,...
User
Verification
User...
User
User
CTAP2 authenticator
with hmac-secret extension
CTAP2 authent...
Password related
Password related
PRF related
PRF related
Long lived keys/data
Long lived keys/da...
Session keys/data
Session keys/data
Generate key
Generate key
Client side storage
Client side storage
Server side storage
Server side storage
PrivateData (reencrypted)
PrivateData (reencrypted)
+ did: string
+ did: string
+ publicKey: JWK
+ publicKey: JWK
+ privateKey: WrappedPrivateKeyInfo
+ privateKey: WrappedPrivateKeyInfo
Text is not SVG - cannot display
\ No newline at end of file