-
-
Notifications
You must be signed in to change notification settings - Fork 220
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
Geoconfig and API settings: AES CBC encryption Migration #35641
Conversation
Values that can't be decrypted are already broken so there is no use in continuing to store it. This will "clear" those values be overriding it with an empty string during migration.
This PR is dependent on #35642 and should not be merged until after that PR is deployed. |
def reencrypted_password_with_cbc(connection): | ||
if connection.password == '': | ||
return '' | ||
elif connection.password.startswith(f'${ALGO_AES}$'): | ||
return reencrypt_ecb_to_cbc_mode(connection.password, f'${ALGO_AES}$') | ||
else: | ||
ciphertext = b64_aes_cbc_encrypt(connection.password) | ||
return f'${ALGO_AES_CBC}${ciphertext}' | ||
|
||
|
||
def reencrypted_client_secret_with_cbc(connection): | ||
if connection.client_secret == '': | ||
return '' | ||
elif connection.client_secret.startswith(f'${ALGO_AES}$'): | ||
return reencrypt_ecb_to_cbc_mode(connection.client_secret, f'${ALGO_AES}$') | ||
else: | ||
ciphertext = b64_aes_cbc_encrypt(connection.client_secret) | ||
return f'${ALGO_AES_CBC}${ciphertext}' | ||
|
||
|
||
def reencrypted_last_token_with_cbc(connection): | ||
if connection.last_token_aes == '': | ||
return '' | ||
elif connection.last_token_aes.startswith(f'${ALGO_AES}$'): | ||
prefix = f'${ALGO_AES}$' | ||
else: | ||
prefix = None | ||
return reencrypt_ecb_to_cbc_mode(connection.last_token_aes, prefix) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This three functions can be one function, the logic is the same, and you can pass connection.password
, connection.client_secret
, connection.last_token_aes
to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be further simplified after you bring some logic to reencrypt_ecb_to_cbc_mode in #35642
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I combined the function for password
and client_secret
here 903d12f. But last_token_aes
needs to be handled differently. The difference being that the stored value is always encrypted but may or may not have the aes-cbc
prefix. For password
and client_secret
, if the value does not contain the prefix, then it is not encrypted. To keep these two lines of logic cleanly separated, I would prefer to keep the functions separate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the change. What do you think of combining the logic, and have a new parameter called reencrypt_only
, reencrypt_only
is True for last_token_aes
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, like this? I have mixed feelings about it, but don't have a strong preference. I can make this change
def _reencrypt_or_encrypt_value_with_cbc(value, reencrypt_only=False):
if value == '':
return ''
if value.startswith(f'${ALGO_AES_CBC}$'):
return value
try:
if value.startswith(f'${ALGO_AES}$'):
return reencrypt_ecb_to_cbc_mode(value, f'${ALGO_AES}$')
else:
if reencrypt_only:
return reencrypt_ecb_to_cbc_mode(value)
else:
ciphertext = b64_aes_cbc_encrypt(value)
return f'${ALGO_AES_CBC}${ciphertext}'
except AesEcbDecryptionError:
return ''
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corehq/motech/migrations/0017_connectionsettings_use_aes_cbc_encryption.py
Show resolved
Hide resolved
corehq/motech/migrations/0017_connectionsettings_use_aes_cbc_encryption.py
Outdated
Show resolved
Hide resolved
corehq/motech/migrations/0017_connectionsettings_use_aes_cbc_encryption.py
Show resolved
Hide resolved
corehq/apps/geospatial/migrations/0009_geoconfig_api_key_cbc_encryption.py
Show resolved
Hide resolved
else: | ||
ciphertext = b64_aes_cbc_encrypt(connection.password) | ||
return f'${ALGO_AES_CBC}${ciphertext}' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these _reencrypted_...
functions also check for .startswith(f'${ALGO_AES_CBC}$')
and skip re-encrypting the value if that returns true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it should. Added this commit to check if the value already contains a aes-cbc prefix and just returns the value if it does. ee61d0f
…een migrated to cbc encryption
corehq/motech/migrations/0017_connectionsettings_use_aes_cbc_encryption.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me
Product Description
N/A
Technical Summary
Continuation of the work initiated by this PR
Jira Ticket
Introduces a solution for these code scan alerts:
https://github.com/dimagi/commcare-hq/security/code-scanning/295
https://github.com/dimagi/commcare-hq/security/code-scanning/296
This PR migrates
GeoConfig
'sapi_token
, andConnectionSettings
'spassword
,client_secret
, andlast_token_aes
. For values that are AES ECB encrypted, this migration reencrypts it with AES CBC. For values that are not encrypted, this migration encrypts it with AES CBC. In both cases, the prefix "$aes-cbc$" is prepended to the encrypted value and saved.Feature Flag
no FF
Safety Assurance
Safety story
locally tested and will test on staging.
Automated test coverage
There exists tests that
reencrypt_ecb_to_cbc_mode
decrypts to the same plaintext value.QA Plan
no QA
Migrations
The migration in this PR is related to this past PR and should not be merged until that PR is deployed.
Rollback instructions
Labels & Review