Repository navigation
Transparent decryption with metadata replacing - #515
Conversation
wrap encoding functions with wrapper that do nothing with valid strings
user struct instead of interface for QueryDataItem to avoid extra nil checks with reflection
weren't used by any component and just produce unused code and complicate reading
…ing/decoding operations over interesting data for decryption/detokenization received from database
extend encryptor, now find ColumnEncryptionSettings for queries from Parse Packet with placeholders and save it in ClientSession to use it in ParameterDescription packet followed by Parse packet (and also for Bind packet but there we already have query to re-parse it)
update OID values according to ColumnEncryptionSetting change value encoding flow for encrypted integers Remove encoding/decoding logic from Column struct, use only from PostgresqlEncoderDecoder and BoundValue encodings
…ta-according-to-data-type
- don't use DecodedData struct - store raw data on protocol handler level - encode/decode data in OnColumn handler on higher level
…g in SQL queries to encrypt bound values
fix parameter description updates
G1gg1L3s
left a comment
There was a problem hiding this comment.
And a few comments and wishes about git history: I think it would be better to split this PR into multiple ones. For example, each item of changes in the description could easily get its own PR. I don't mind if these small PRs would contain only change of a single line of code, because it would greatly improve the quality and speed of reviews: it's easier to separate changes and think why they are important on their own. Also, I like reading not only the final changes, but all commits one by one, to understand the logic about how and reasons why something is changing. But it was hard, because the commits often contain multiple changes at once, or are the parts of other commits. Very often they, beside some changes, they contain formatting fixes or commented code. For formatting I would recommend setup something like format on save or format on commit or something similar. Also I recommend reading about best practices about commit messages https://cbea.ms/git-commit
P.S. Sorry if some comments are outdated. They were written during the review of commits one by one, so some changes could happen in the next commits, that weren't reviewed yet.
| for j, value := range valTuple { | ||
| columnName := columnsName[j] | ||
| if changedValue, err := encryptor.encryptExpression(ctx, value, schema, columnName); err != nil { | ||
| columnName := columnsName[j%len(columnsName)] |
There was a problem hiding this comment.
Why is there a modulo operation?
There was a problem hiding this comment.
There was a problem hiding this comment.
we use module because there should be not more than declared columns count:
insert into table1(col1, col2, col3) values (val1, val2, val3), (val4, val5, val6);
There is we have 3 columns and 3 tuples. Every tuple can have 3 values. If more than it's invalid behavior and we can skip it and pass as is to database. Because database will deny such query. But in valid case we are safe and map value to correct column.
There was a problem hiding this comment.
Ok, this is reasonable. But in my opinion, it would be better to just check that if j > len(columnNames) then just skip this iteration with continue. At least we will not spend time encrypting extra values.
Lagovas
left a comment
There was a problem hiding this comment.
And a few comments and wishes about git history: I think it would be better to split this PR into multiple ones. For example, each item of changes in the description could easily get its own PR. I don't mind if these small PRs would contain only change of a single line of code, because it would greatly improve the quality and speed of reviews: it's easier to separate changes and think why they are important on their own. Also, I like reading not only the final changes, but all commits one by one, to understand the logic about how and reasons why something is changing. But it was hard, because the commits often contain multiple changes at once, or are the parts of other commits. Very often they, beside some changes, they contain formatting fixes or commented code. For formatting I would recommend setup something like format on save or format on commit or something similar. Also I recommend reading about best practices about commit messages https://cbea.ms/git-commit
P.S. Sorry if some comments are outdated. They were written during the review of commits one by one, so some changes could happen in the next commits, that weren't reviewed yet.
agree with you, will try it in next my PRs. This feature wasn't clear at the start and a lot of things were changed during the development due to existing of a lot of components linked with each other. but looking at now I see that there a lot of pieces that could be splitted into separate PRs easily *(
you prefer that I will fix current comments, commit, wait approval and after that split it into the separate PRs and review one more time or we can finish it as is and keep it in mind in the future?)
p.s. about auto-format. I already have it. But it has a small sleep before applying (to not format on every new character) and sometimes when I switch into the next tab/window after changes my IDE fails to format code) So, I will add it to pre-commit hooks to avoid such problems.
| // If the configuration file contains some unknown or unsupported token type, | ||
| // return some safe default. |
There was a problem hiding this comment.
it validated here -
acra/encryptor/config/encryptionSettings.go
Line 259 in d2c125c
And this function only as
Getter for the field. Errors may occur in tests where such structs are initialized by value
I think we can left this PR as is :) |
common package decryptor/base
…ta-according-to-data-type
G1gg1L3s
left a comment
There was a problem hiding this comment.
Beside one comment, everything is cool!
| // collect placeholder in queries to save for future ParameterDescription packet to replace according to | ||
| // setting's data type | ||
| // | ||
| // 32 as initial size to avoid future re-allocation. looks like enough for a lot of apps |
There was a problem hiding this comment.
Seems like a leftover comment
[skip ci]
| size = 4 | ||
| } | ||
| // convert back from text to binary | ||
| value, err := strconv.ParseInt(string(data), 10, 64) |
There was a problem hiding this comment.
Small question: in all other cases we first check that value is indeed decrypted (by calling base.IsDecryptedFromContext(ctx)), and if not, we fallback to returning default values. But in this case we check decryption by parsing the number. Does it have some special meaning or reason?
There was a problem hiding this comment.
the main reason is that any encrypted blob has size > len('9223372036854775807') = 19. Our acrablock has 90+ bytes of overhead. Acrastructs even more. So no one supported ciphertext cannot be valid integer string literal. So there is enough to check that it's valid valid integer string literal.

DataRowDescriptionandParameterDescriptionData. InDataRowDescriptionnow we replaceOIDvalues that tell drivers which data types will be returned. InParameterDescriptionDatawe replaceOIDs for parameters in prepared statements. To tell apps that they should pass string value instead of binary (that will be changed on Acra side)default_data_valueanddata_type. Last values generated via protobuf in similar way as token type.QueryDataEncryptorto re-use functions related to parsing placeholders and saving encryptor's settings in context/client session valuesClientSessioninterface to provide KV interface and store session related data for client/db packet handlersacra-log-verifierconfig file from configs folderctx) with flag after successful decryption (base.[MarkDecryptedContext|IsDecryptedFromContext]). Needs for replacing with default values binary data types that hard to determine when they was untouchedSubscribeOnColumnDecryptionand all related methods of proxies due to not usingPgSQLDataEncoderProcessor. Now it used not only for tokenization, but for decoding all input data from database and encoding before sending to client. Also removed this logic fromPostgresqlDecryptorwhich now responsible only for database packet parsing. All other data manipulations moved to OnQuery/OnBind/OnColumn subscribersDecodedDatawrapper forColumnstructs used by decryptorIt's ready to review. Probably last changes will be related to encryptor's config validation and updating changelogs (after that I will change it from status
Draft). So welcome to review.Checklist
with new changes
[ ] Benchmark results are attached (if applicable)[ ] Example projects and code samples are up-to-date (in case of API changes)