Skip to content

Commit

Permalink
Fix Blake2b hash (#5089)
Browse files Browse the repository at this point in the history
Signed-off-by: Terry Quigley <[email protected]>
  • Loading branch information
terryquigleysas authored Mar 3, 2025
1 parent 9e47728 commit d43f96c
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.opensearch.security.user.User;
import org.opensearch.test.framework.TestSecurityConfig;

import static org.opensearch.security.privileges.dlsfls.FieldMasking.Config.BLAKE2B_LEGACY_DEFAULT;
import static org.opensearch.security.util.MockIndexMetadataBuilder.indices;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
Expand Down Expand Up @@ -141,6 +142,18 @@ public void simple() throws Exception {
assertNull(expression.getRegexReplacements());

FieldMasking.FieldMaskingRule.Field field = new FieldMasking.FieldMaskingRule.Field(expression, FieldMasking.Config.DEFAULT);
assertEquals("c042e214a8b49561577445be44c188a8e6274006b36cd0c6fba5312253cf9293", field.apply("foobar"));
}

@Test
public void simple_legacyDefaultAlgorithm() throws Exception {
FieldMasking.FieldMaskingExpression expression = new FieldMasking.FieldMaskingExpression("field_*");
FieldMasking.FieldMaskingRule.Field field = new FieldMasking.FieldMaskingRule.Field(
expression,
FieldMasking.Config.fromSettings(
Settings.builder().put("plugins.security.masked_fields.algorithm.default", BLAKE2B_LEGACY_DEFAULT).build()
)
);
assertEquals("96c8d1da7eb153db858d4f0585120319e17ed1162db9e94bee19fb10b6d19727", field.apply("foobar"));
}

Expand Down Expand Up @@ -260,9 +273,9 @@ public void simple() throws Exception {
assertFalse("FieldMasking.FieldMaskingRule should return false for isAllowAll()", rule.isAllowAll());
assertTrue("Rule applies to field field_masked_1", rule.isMasked("field_masked_1"));
assertFalse("Rule does not apply to field field_other", rule.isMasked("field_other"));
assertEquals("96c8d1da7eb153db858d4f0585120319e17ed1162db9e94bee19fb10b6d19727", rule.get("field_masked_1").apply("foobar"));
assertEquals("c042e214a8b49561577445be44c188a8e6274006b36cd0c6fba5312253cf9293", rule.get("field_masked_1").apply("foobar"));
assertEquals(
new BytesRef("96c8d1da7eb153db858d4f0585120319e17ed1162db9e94bee19fb10b6d19727".getBytes(StandardCharsets.UTF_8)),
new BytesRef("c042e214a8b49561577445be44c188a8e6274006b36cd0c6fba5312253cf9293".getBytes(StandardCharsets.UTF_8)),
rule.get("field_masked_1").apply(new BytesRef("foobar".getBytes(StandardCharsets.UTF_8)))
);
assertEquals("FM:[field_masked_*]", rule.toString());
Expand All @@ -275,7 +288,7 @@ public void keyword() throws Exception {
assertTrue("Rule applies to field field_masked_1", rule.isMasked("field_masked"));
assertTrue("Rule applies to field field_masked_1.keyword", rule.isMasked("field_masked.keyword"));
assertEquals(
"96c8d1da7eb153db858d4f0585120319e17ed1162db9e94bee19fb10b6d19727",
"c042e214a8b49561577445be44c188a8e6274006b36cd0c6fba5312253cf9293",
rule.get("field_masked.keyword").apply("foobar")
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public void maskSimpleAttribute() throws Exception {
String expectedDocument = """
{
"a": "x",
"b": "1147ddc9246d856b1ce322f1dc9eeda895b56d545c324510c2eca47a9dcc5d3f",
"b": "4b694e9cb9ce9e0983fbe4c5df2d464949610f074460adc76bda5a9d0bcc38a5",
"c": "z"
}
""";
Expand Down Expand Up @@ -351,7 +351,7 @@ public void maskObjectAttribute() throws Exception {
{
"a": "x",
"b": {
"b1": "19937da9d0b0fb38c3ce369bed130b647fa547914d675e09a62ba260a6d7811b",
"b1": "f16d01664d4270a4f39cdba8c89ac024380b5f249f0fbec1049497bc745cf30f",
"b2": "y2"
},
"c": "z"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@

import static org.opensearch.security.dlic.rest.api.RestApiAdminPrivilegesEvaluator.ENDPOINTS_WITH_PERMISSIONS;
import static org.opensearch.security.dlic.rest.api.RestApiAdminPrivilegesEvaluator.SECURITY_CONFIG_UPDATE;
import static org.opensearch.security.privileges.dlsfls.FieldMasking.Config.BLAKE2B_LEGACY_DEFAULT;
import static org.opensearch.security.setting.DeprecatedSettings.checkForDeprecatedSetting;
import static org.opensearch.security.support.ConfigConstants.OPENDISTRO_SECURITY_AUTHENTICATED_USER;
import static org.opensearch.security.support.ConfigConstants.SECURITY_ALLOW_DEFAULT_INIT_SECURITYINDEX;
Expand Down Expand Up @@ -448,7 +449,7 @@ public List<Path> run() {

try {
String maskingAlgorithmDefault = settings.get(ConfigConstants.SECURITY_MASKED_FIELDS_ALGORITHM_DEFAULT);
if (StringUtils.isNotEmpty(maskingAlgorithmDefault)) {
if (StringUtils.isNotEmpty(maskingAlgorithmDefault) && !BLAKE2B_LEGACY_DEFAULT.equalsIgnoreCase(maskingAlgorithmDefault)) {
MessageDigest.getInstance(maskingAlgorithmDefault);
}
} catch (Exception ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,14 @@ public static class Field {
private final String hashAlgorithm;
private final Salt salt;
private final byte[] saltBytes;
private final boolean useLegacyDefaultAlgorithm;

Field(FieldMaskingExpression expression, FieldMasking.Config fieldMaskingConfig) {
this.expression = expression;
this.hashAlgorithm = expression.getAlgoName() != null ? expression.getAlgoName()
: StringUtils.isNotEmpty(fieldMaskingConfig.getDefaultHashAlgorithm()) ? fieldMaskingConfig.getDefaultHashAlgorithm()
: null;
this.useLegacyDefaultAlgorithm = fieldMaskingConfig.useLegacyDefaultAlgorithm();
this.salt = fieldMaskingConfig.getSalt();
this.saltBytes = this.salt.getSalt16();
}
Expand All @@ -252,10 +254,12 @@ public WildcardMatcher getPattern() {
public byte[] apply(byte[] value) {
if (expression.getRegexReplacements() != null) {
return applyRegexReplacements(value, expression.getRegexReplacements());
} else if (this.useLegacyDefaultAlgorithm) {
return blake2bHash(value, true);
} else if (this.hashAlgorithm != null) {
return customHash(value, this.hashAlgorithm);
} else {
return blake2bHash(value);
return blake2bHash(value, false);
}
}

Expand Down Expand Up @@ -301,10 +305,13 @@ private byte[] applyRegexReplacements(byte[] value, List<FieldMaskingExpression.
return string.getBytes(StandardCharsets.UTF_8);
}

private byte[] blake2bHash(byte[] in) {
// Salt is passed incorrectly but order of parameters is retained at present to ensure full backwards compatibility
// Tracking with https://github.com/opensearch-project/security/issues/4274
final Blake2b hash = new Blake2b(null, 32, null, saltBytes);
private byte[] blake2bHash(byte[] in, boolean useLegacyDefaultAlgorithm) {
final Blake2b hash;
if (useLegacyDefaultAlgorithm) {
hash = new Blake2b(null, 32, null, saltBytes);
} else {
hash = new Blake2b(null, 32, saltBytes, null);
}
hash.update(in, 0, in.length);
final byte[] out = new byte[hash.getDigestSize()];
hash.digest(out, 0);
Expand Down Expand Up @@ -461,6 +468,8 @@ String getSource() {
}

public static class Config {
public static final String BLAKE2B_LEGACY_DEFAULT = "BLAKE2B_LEGACY_DEFAULT";

public static Config fromSettings(Settings settings) {
return new Config(settings.get(ConfigConstants.SECURITY_MASKED_FIELDS_ALGORITHM_DEFAULT), Salt.from(settings));
}
Expand All @@ -469,10 +478,12 @@ public static Config fromSettings(Settings settings) {

private final String defaultHashAlgorithm;
private final Salt salt;
private final boolean useLegacyDefaultAlgorithm;

Config(String defaultHashAlgorithm, Salt salt) {
this.defaultHashAlgorithm = defaultHashAlgorithm;
this.salt = salt;
this.useLegacyDefaultAlgorithm = BLAKE2B_LEGACY_DEFAULT.equalsIgnoreCase(defaultHashAlgorithm);
}

public String getDefaultHashAlgorithm() {
Expand All @@ -482,6 +493,10 @@ public String getDefaultHashAlgorithm() {
public Salt getSalt() {
return salt;
}

public boolean useLegacyDefaultAlgorithm() {
return useLegacyDefaultAlgorithm;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ public void testComplexMappingSearch() throws Exception {
"88783587fef740690c4fa39476fb86314d034fa3370e1a1fa186f6d9d4644a18ad85063c1e3161f8929f7ca019bb8740611eaf337709113901e7c3a6b59f4166"
)
);
Assert.assertFalse(res.getBody().contains("e90a2fdf7b1939ec06e294321fd7d23e1a70d8fc080a3f85d0f3bf08c205b53"));
Assert.assertFalse(res.getBody().contains("9fe023e13d5179157b2023c21c60bc98340a12470538affd306281619d2477c3"));
Assert.assertFalse(res.getBody().contains("*.*.*.*"));
Assert.assertFalse(res.getBody().contains("430a65d4b9c51de7192e048b2639db0de5c56f1901afccc2a01ef97f6a769a38"));
Assert.assertFalse(res.getBody().contains("7f48bb3636edf546a75968ca7cd0bdfe63e9ce7af04ef7cb642931fa15d2d7a3"));
Assert.assertFalse(res.getBody().contains("5115e9707d1a18772af2a1274e2d3450284754a921692d6b1aef922c33cda8fa"));
Assert.assertFalse(res.getBody().contains("8915d31ba2e0ac9eea0c8af1beb058dfa3d01147c233ede320d441cc1b65fa33"));
Assert.assertFalse(res.getBody().contains("https://www.static.co/downloads/beats/metricbeat"));
Assert.assertFalse(
res.getBody()
Expand Down Expand Up @@ -207,10 +207,10 @@ public void testComplexMappingSearch() throws Exception {
"88783587fef740690c4fa39476fb86314d034fa3370e1a1fa186f6d9d4644a18ad85063c1e3161f8929f7ca019bb8740611eaf337709113901e7c3a6b59f4166"
)
);
Assert.assertTrue(res.getBody().contains("e90a2fdf7b1939ec06e294321fd7d23e1a70d8fc080a3f85d0f3bf08c205b53"));
Assert.assertTrue(res.getBody().contains("9fe023e13d5179157b2023c21c60bc98340a12470538affd306281619d2477c3"));
Assert.assertTrue(res.getBody().contains("*.*.*.*"));
Assert.assertTrue(res.getBody().contains("430a65d4b9c51de7192e048b2639db0de5c56f1901afccc2a01ef97f6a769a38"));
Assert.assertTrue(res.getBody().contains("7f48bb3636edf546a75968ca7cd0bdfe63e9ce7af04ef7cb642931fa15d2d7a3"));
Assert.assertTrue(res.getBody().contains("5115e9707d1a18772af2a1274e2d3450284754a921692d6b1aef922c33cda8fa"));
Assert.assertTrue(res.getBody().contains("8915d31ba2e0ac9eea0c8af1beb058dfa3d01147c233ede320d441cc1b65fa33"));
Assert.assertTrue(res.getBody().contains("https://www.static.co/downloads/beats/metricbeat"));
Assert.assertTrue(
res.getBody()
Expand All @@ -236,9 +236,9 @@ public void testComplexMappingSearch() throws Exception {
"88783587fef740690c4fa39476fb86314d034fa3370e1a1fa186f6d9d4644a18ad85063c1e3161f8929f7ca019bb8740611eaf337709113901e7c3a6b59f4166"
)
);
Assert.assertFalse(res.getBody().contains("e90a2fdf7b1939ec06e294321fd7d23e1a70d8fc080a3f85d0f3bf08c205b53"));
Assert.assertFalse(res.getBody().contains("9fe023e13d5179157b2023c21c60bc98340a12470538affd306281619d2477c3"));
Assert.assertFalse(res.getBody().contains("*.*.*.*"));
Assert.assertFalse(res.getBody().contains("430a65d4b9c51de7192e048b2639db0de5c56f1901afccc2a01ef97f6a769a38"));
Assert.assertFalse(res.getBody().contains("8915d31ba2e0ac9eea0c8af1beb058dfa3d01147c233ede320d441cc1b65fa33"));
Assert.assertFalse(res.getBody().contains("7f48bb3636edf546a75968ca7cd0bdfe63e9ce7af04ef7cb642931fa15d2d7a3"));
Assert.assertFalse(res.getBody().contains("https://www.static.co/downloads/beats/metricbeat"));
Assert.assertFalse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ public void testDFMRestrictedUser() throws Exception {
Assert.assertFalse(response.getBody().contains("value-2-4"));

// field2 - check also some masked values
Assert.assertTrue(response.getBody().contains("514b27191e2322b0f7cd6afc3a5d657ff438fd0cc8dc229bd1a589804fdffd99"));
Assert.assertTrue(response.getBody().contains("3090f7e867f390fb96b20ba30ee518b09a927b857393ebd1262f31191a385efa"));
Assert.assertTrue(response.getBody().contains("b83363be1efc9a30269963686915db175630744f7b9b53eaf012275c10028ed8"));
Assert.assertTrue(response.getBody().contains("1036e0c7154ead29670a4d0a609727aeec7e6f39a97b72053d49255b5865e341"));
}

/**
Expand Down Expand Up @@ -271,7 +271,7 @@ public void testDFMRestrictedAndUnrestrictedOneIndex() throws Exception {
Assert.assertTrue(response.getBody().contains("value-2-4"));

// but we still have masked values for index1-2 and index1-3
Assert.assertTrue(response.getBody().contains("514b27191e2322b0f7cd6afc3a5d657ff438fd0cc8dc229bd1a589804fdffd99"));
Assert.assertTrue(response.getBody().contains("3090f7e867f390fb96b20ba30ee518b09a927b857393ebd1262f31191a385efa"));
Assert.assertTrue(response.getBody().contains("b83363be1efc9a30269963686915db175630744f7b9b53eaf012275c10028ed8"));
Assert.assertTrue(response.getBody().contains("1036e0c7154ead29670a4d0a609727aeec7e6f39a97b72053d49255b5865e341"));
}
}
Loading

0 comments on commit d43f96c

Please sign in to comment.