-
Notifications
You must be signed in to change notification settings - Fork 27
feat: Support Ed25519 key #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
e2725c3
support Edwards key
dimei-BT 2f55f5d
Merge remote-tracking branch 'upstream/master'
dimei-BT 99c063e
create an api key helper
dimei-BT c747810
lint error fix
dimei-BT 11298ae
addressing comments
dimei-BT a60b4e1
addressing comments
dimei-BT b201134
add an entry to CHANGELOG
dimei-BT File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import base64 | ||
|
|
||
| from cryptography.hazmat.primitives import serialization | ||
| from cryptography.hazmat.primitives.asymmetric import ed25519 | ||
|
|
||
|
|
||
| def _parse_private_key(key_str: str): | ||
| """Parse a private key from a given string representation. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| key_str : str | ||
| A string representing the private key. This should be either a PEM-encoded | ||
| key (for ECDSA keys) or a base64-encoded string (for Ed25519 keys). | ||
|
|
||
| Returns | ||
| ------- | ||
| An instance of a private key | ||
|
|
||
| Raises | ||
| ------ | ||
| ValueError | ||
| If the key cannot be parsed as a valid PEM-encoded key or a base64-encoded Ed25519 private key. | ||
|
|
||
| """ | ||
| key_data = key_str.encode() | ||
| try: | ||
| return serialization.load_pem_private_key(key_data, password=None) | ||
| except Exception: | ||
| try: | ||
| decoded_key = base64.b64decode(key_str) | ||
| if len(decoded_key) == 32: | ||
| return ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key) | ||
| elif len(decoded_key) == 64: | ||
| return ed25519.Ed25519PrivateKey.from_private_bytes(decoded_key[:32]) | ||
| else: | ||
| raise ValueError("Ed25519 private key must be 32 or 64 bytes after base64 decoding") | ||
| except Exception as e: | ||
| raise ValueError("Could not parse the private key") from e | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import base64 | ||
|
|
||
| import pytest | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def dummy_key_factory(): | ||
| """Create and return a factory function for generating dummy keys for testing. | ||
|
|
||
| The factory accepts a `key_type` parameter with the following options: | ||
| - "ecdsa": Returns a PEM-encoded ECDSA private key. | ||
| - "ed25519-32": Returns a base64-encoded 32-byte Ed25519 private key. | ||
| - "ed25519-64": Returns a base64-encoded 64-byte dummy Ed25519 key (the first 32 bytes will be used). | ||
| """ | ||
| def _create_dummy(key_type: str = "ecdsa") -> str: | ||
| if key_type == "ecdsa": | ||
| return ( | ||
| "-----BEGIN EC PRIVATE KEY-----\n" | ||
| "MHcCAQEEIMM75bm9WZCYPkfjXSUWNU5eHx47fWM2IpG8ki90BhRDoAoGCCqGSM49\n" | ||
| "AwEHoUQDQgAEicwlaAqy7Z4SS7lvrEYoy6qR9Kf0n0jFzg+XExcXKU1JMr18z47W\n" | ||
| "5mrftEqWIqPCLQ16ByoKW2Bsup5V3q9P4g==\n" | ||
| "-----END EC PRIVATE KEY-----\n" | ||
| ) | ||
| elif key_type == "ed25519-32": | ||
| return "BXyKC+eFINc/6ztE/3neSaPGgeiU9aDRpaDnAbaA/vyTrUNgtuh/1oX6Vp+OEObV3SLWF+OkF2EQNPtpl0pbfA==" | ||
| elif key_type == "ed25519-64": | ||
| # Create a 64-byte dummy by concatenating a 32-byte sequence with itself. | ||
| dummy_32 = b'\x01' * 32 | ||
| dummy_64 = dummy_32 + dummy_32 | ||
| return base64.b64encode(dummy_64).decode("utf-8") | ||
| else: | ||
| raise ValueError("Unsupported key type for dummy key creation") | ||
| return _create_dummy |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import pytest | ||
| from cryptography.hazmat.primitives.asymmetric import ec, ed25519 | ||
|
|
||
| from cdp.api_key_utils import _parse_private_key | ||
|
|
||
|
|
||
| def test_parse_private_key_pem_ec(dummy_key_factory): | ||
| """Test that a PEM-encoded ECDSA key is parsed correctly using a dummy key from the factory.""" | ||
| dummy_key = dummy_key_factory("ecdsa") | ||
| parsed_key = _parse_private_key(dummy_key) | ||
| assert isinstance(parsed_key, ec.EllipticCurvePrivateKey) | ||
|
|
||
| def test_parse_private_key_ed25519_32(dummy_key_factory): | ||
| """Test that a base64-encoded 32-byte Ed25519 key is parsed correctly using a dummy key from the factory.""" | ||
| dummy_key = dummy_key_factory("ed25519-32") | ||
| parsed_key = _parse_private_key(dummy_key) | ||
| assert isinstance(parsed_key, ed25519.Ed25519PrivateKey) | ||
|
|
||
| def test_parse_private_key_ed25519_64(dummy_key_factory): | ||
| """Test that a base64-encoded 64-byte input is parsed correctly by taking the first 32 bytes using a dummy key from the factory.""" | ||
| dummy_key = dummy_key_factory("ed25519-64") | ||
| parsed_key = _parse_private_key(dummy_key) | ||
| assert isinstance(parsed_key, ed25519.Ed25519PrivateKey) | ||
|
|
||
| def test_parse_private_key_invalid(): | ||
| """Test that an invalid key string raises a ValueError.""" | ||
| with pytest.raises(ValueError, match="Could not parse the private key"): | ||
| _parse_private_key("invalid_key") |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.