Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 21 additions & 45 deletions lib/src/udf_dart_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,13 @@ UdfTypeIdentifier typeId(DigestAlgorithm digestAlgorithm, int compression) {
}
break;
default:
throw ArgumentError(
'Unexpected algorithm: ' + digestAlgorithm.toString());
throw ArgumentError('Unexpected algorithm: ' + digestAlgorithm.toString());
}
}

UdfTypeIdentifier idFromValue(int value) {
return UdfTypeIdentifier.values.firstWhere((e) => idCode(e) == value,
orElse: () => throw ArgumentError(
'Unexpected UdfTypeIdentifier code: ' + value.toString()));
orElse: (() => throw ArgumentError('Unexpected UdfTypeIdentifier code: ' + value.toString())) as UdfTypeIdentifier Function()?);
}

class UDF {
Expand All @@ -184,12 +182,8 @@ class UDF {
/// [contentType] MIME media type. See
/// http://www.iana.org/assignments/media-types/media-types.xhtml for list.
/// SHA2-512 (UTF8(ContentType) + ":" + SHA2512(Data))
static List<int> udfBuffer(
final List<int> dataDigest, final String contentType) {
return sha512
.newInstance()
.convert(udfDataBuffer(dataDigest, contentType))
.bytes;
static List<int> udfBuffer(final List<int> dataDigest, final String contentType) {
return sha512.convert(udfDataBuffer(dataDigest, contentType)).bytes;
}

/// Calculate a UDF fingerprint from the content data with specified precision.
Expand All @@ -201,22 +195,18 @@ class UDF {
/// [key] Optional key used to create a keyed fingerprint.
/// Returns The binary UDF fingerprint.
static List<int> dataToUDFBinary(List<int> data, String contentType,
{int precision = 0,
DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA2_512,
String key}) {
{int precision = 0, DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA2_512, String? key}) {
switch (digestAlgorithm) {
case DigestAlgorithm.SHA2_512:
// H(<Data>)
var sha512Digest = sha512.newInstance().convert(data).bytes;
var sha512Digest = sha512.convert(data).bytes;
// H(<Content-ID> + ':' + H(<Data>))
return digestToUDFBinary(sha512Digest, contentType,
precision: precision, digestAlgorithm: digestAlgorithm, key: key);
return digestToUDFBinary(sha512Digest, contentType, precision: precision, digestAlgorithm: digestAlgorithm, key: key);
break;
case DigestAlgorithm.SHA3_512:
throw ArgumentError('SHA3_512 not implemented');
default:
throw ArgumentError(
'Unexpected algorithm: ' + digestAlgorithm.toString());
throw ArgumentError('Unexpected algorithm: ' + digestAlgorithm.toString());
}
}

Expand All @@ -229,11 +219,8 @@ class UDF {
/// the hash value.
/// [key] Optional key used to create a keyed fingerprint.
/// Returns the binary UDF fingerprint
static List<int> digestToUDFBinary(
final List<int> digest, final String contentType,
{int precision = 0,
DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA2_512,
String key}) {
static List<int> digestToUDFBinary(final List<int> digest, final String contentType,
{int precision = 0, DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA2_512, String? key}) {
switch (digestAlgorithm) {
case DigestAlgorithm.SHA2_512:
// H(<Content-ID> + ':' + H(<Data>))
Expand All @@ -242,8 +229,7 @@ class UDF {
case DigestAlgorithm.SHA3_512:
throw ArgumentError('SHA3_512 not implemented');
default:
throw ArgumentError(
'Unexpected algorithm: ' + digestAlgorithm.toString());
throw ArgumentError('Unexpected algorithm: ' + digestAlgorithm.toString());
}
}

Expand All @@ -256,9 +242,7 @@ class UDF {
/// [key] Key used to create a keyed fingerprint.
/// @return The binary UDF fingerprint.
static List<int> bufferDigestToUDF(List<int> digest,
{int precision = 0,
DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA2_512,
String key}) {
{int precision = 0, DigestAlgorithm digestAlgorithm = DigestAlgorithm.SHA2_512, String? key}) {
if (key == null) {
// Data UDF
var typeIdentifier = typeId(digestAlgorithm, getCompression(digest));
Expand All @@ -268,14 +252,11 @@ class UDF {
switch (digestAlgorithm) {
case DigestAlgorithm.SHA2_512:
var udfData = Hmac(sha512, utf8.encode(key)).convert(digest).bytes;
return typeBDSToBinary(
UdfTypeIdentifier.Authenticator_HMAC_SHA_2_512, udfData,
precision: precision);
return typeBDSToBinary(UdfTypeIdentifier.Authenticator_HMAC_SHA_2_512, udfData, precision: precision);
case DigestAlgorithm.SHA3_512:
throw ArgumentError('SHA3_512 not implemented');
default:
throw ArgumentError(
'Unexpected algorithm: ' + digestAlgorithm.toString());
throw ArgumentError('Unexpected algorithm: ' + digestAlgorithm.toString());
}
}
}
Expand All @@ -289,12 +270,10 @@ class UDF {
/// of the property [defaultBits] is used.
/// [offset] Offset in [source]
/// Retuns the resulting binary buffer.
static List<int> typeBDSToBinary(UdfTypeIdentifier typeID, List<int> source,
{int precision = defaultBits, int offset = 0}) {
static List<int> typeBDSToBinary(UdfTypeIdentifier typeID, List<int> source, {int precision = defaultBits, int offset = 0}) {
// Constraints the number of bits to an integer multiple of 20 bits between
// DefaultBits and MaximumBits.
precision =
min((precision <= 0 ? defaultBits : precision), source.length * 8);
precision = min((precision <= 0 ? defaultBits : precision), source.length * 8);

// Calculate the number of bytes
var bytes = ((precision + 7) ~/ 8);
Expand Down Expand Up @@ -346,9 +325,8 @@ class UDF {
/// [charsPerBlock] number of chars to be printed per block
/// [delimiter] delimiter character
/// [precision] the presision to be printed. Multiple of 5bits * [charsPerBlock]
static String printBase32(List<int> udfBytes,
{int charsPerBlock = 5, String delimiter = '-', int precision = -1}) {
var encoded = base32.encode(udfBytes);
static String printBase32(List<int> udfBytes, {int charsPerBlock = 5, String delimiter = '-', int precision = -1}) {
var encoded = base32.encode(udfBytes as Uint8List);
var endIndex = encoded.indexOf('=');
var base32String = endIndex > 0 ? encoded.substring(0, endIndex) : encoded;
var blocks = chunk(base32String, charsPerBlock);
Expand All @@ -370,8 +348,7 @@ class UDF {
static List<String> chunk(String string, int charsPerBlock) {
var chunks = <String>[];
for (var start = 0; start < string.length; start += charsPerBlock) {
chunks.add(
string.substring(start, min(string.length, start + charsPerBlock)));
chunks.add(string.substring(start, min(string.length, start + charsPerBlock)));
}
return chunks;
}
Expand All @@ -381,8 +358,7 @@ class UDF {
/// [digest] the data digest H(<Data>)
/// [contentType] the content type <Content-ID>
/// return <Content-ID> + ':' + H(<Data>)
static List<int> udfDataBuffer(
final List<int> digest, final String contentType) {
static List<int> udfDataBuffer(final List<int> digest, final String contentType) {
var resultBuffer = List<int>.from(utf8.encode(contentType));
resultBuffer.add(tagSeparatorByte);
resultBuffer.addAll(digest);
Expand All @@ -394,7 +370,7 @@ class UDF {
return List<int>.generate((bits - 8) ~/ 8, (i) => random.nextInt(256));
}

static List<int> nonce({List<int> data, int bits}) {
static List<int> nonce({List<int>? data, int? bits}) {
bits ??= defaultBits;
data ??= nonceData(bits);
return typeBDSToBinary(UdfTypeIdentifier.Nonce, data, precision: bits);
Expand Down
8 changes: 4 additions & 4 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ description: A starting point for Dart libraries or applications.
# homepage: https://www.example.com

environment:
sdk: '>=2.8.1 <3.0.0'
sdk: '>=2.12.0-0 <3.0.0'

dependencies:
base32: 1.1.2
base32: ^2.0.0

dev_dependencies:
pedantic: ^1.9.0
test: ^1.14.4
pedantic: ^1.11.1
test: ^1.17.9
52 changes: 15 additions & 37 deletions test/udf_dart_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,70 +24,54 @@ void main() {
});

test('testSHA2Digest hex print sha512 of data H(<Data>)', () {
var sha512Bytes = sha512
.newInstance()
.convert(utf8.encode('UDF Compressed Document 4187123'))
.bytes;
var sha512Bytes = sha512.convert(utf8.encode('UDF Compressed Document 4187123')).bytes;
const expected =
'36 21 FA 2A C5 D8 62 5C 2D 0B 45 FB 65 93 FC 69 C1 ED F7 00 AE 6F E3 3D 38 13 FE AB 76 AA 74 13 6D 5A 2B 20 DE D6 A5 CF 6C 04 E6 56 3F F3 C0 C7 C4 1D 3F 43 DD DC F1 A5 67 A7 E0 67 9A B0 C6 B7';
expect(hexPrintBytes(sha512Bytes), expected);
});

test('udfDataBufferTest hex print udf <Content-ID> + <:> + H(<Data>)', () {
var dataDigest = sha512
.newInstance()
.convert(utf8.encode('UDF Compressed Document 4187123'))
.bytes;
var dataDigest = sha512.convert(utf8.encode('UDF Compressed Document 4187123')).bytes;
var udfDataBuffer = UDF.udfDataBuffer(dataDigest, 'text/plain');
const expected =
'74 65 78 74 2F 70 6C 61 69 6E 3A 36 21 FA 2A C5 D8 62 5C 2D 0B 45 FB 65 93 FC 69 C1 ED F7 00 AE 6F E3 3D 38 13 FE AB 76 AA 74 13 6D 5A 2B 20 DE D6 A5 CF 6C 04 E6 56 3F F3 C0 C7 C4 1D 3F 43 DD DC F1 A5 67 A7 E0 67 9A B0 C6 B7';
expect(hexPrintBytes(udfDataBuffer), expected);
});

test('udfDataBufferTest2 H(<Content-ID> + <:> + H(<Data>))', () {
var dataDigest = sha512
.newInstance()
.convert(utf8.encode('UDF Compressed Document 4187123'))
.bytes;
var dataDigest = sha512.convert(utf8.encode('UDF Compressed Document 4187123')).bytes;
var udfDataBuffer = UDF.udfDataBuffer(dataDigest, 'text/plain');
var bufferDigest = sha512.newInstance().convert(udfDataBuffer).bytes;
var bufferDigest = sha512.convert(udfDataBuffer).bytes;
const expected =
'8E 14 D9 19 4E D6 02 12 C3 30 A7 BB 5F C7 17 6D AE 9A 56 7C A8 2A 23 1F 96 75 ED 53 10 EC E8 F2 60 14 24 D0 C8 BC 55 3D C0 70 F7 5E 86 38 1A 0B CB 55 9C B2 87 81 27 FF 3C EC E2 F0 90 A0 00 00';
expect(hexPrintBytes(bufferDigest), expected);
});

test('udfBSDDataBufferTest2 testing compression, by', () {
var dataDigest = sha512
.newInstance()
.convert(utf8.encode('UDF Compressed Document 4187123'))
.bytes;
var dataDigest = sha512.convert(utf8.encode('UDF Compressed Document 4187123')).bytes;
var udfDataBuffer = UDF.udfDataBuffer(dataDigest, 'text/plain');
var bufferDigest = sha512.newInstance().convert(udfDataBuffer).bytes;
var bufferDigest = sha512.convert(udfDataBuffer).bytes;
var compression = UDF.getCompression(bufferDigest);
expect(compression, 1);

var typeID = typeId(DigestAlgorithm.SHA2_512, compression);
expect(typeID, UdfTypeIdentifier.Digest_SHA_2_512_20);

var udfTypedBuffer =
UDF.typeBDSToBinary(typeID, bufferDigest, precision: 800);
var udfTypedBuffer = UDF.typeBDSToBinary(typeID, bufferDigest, precision: 800);
const expected =
'61 8E 14 D9 19 4E D6 02 12 C3 30 A7 BB 5F C7 17 6D AE 9A 56 7C A8 2A 23 1F 96 75 ED 53 10 EC E8 F2 60 14 24 D0 C8 BC 55 3D C0 70 F7 5E 86 38 1A 0B CB 55 9C B2 87 81 27 FF 3C EC E2 F0 90 A0 00';
expect(hexPrintBytes(udfTypedBuffer), expected);
});

test('udfBSDDataBufferTest3', () {
var udfTypedBuffer = UDF.dataToUDFBinary(
utf8.encode('UDF Compressed Document 4187123'), 'text/plain',
precision: 800);
var udfTypedBuffer = UDF.dataToUDFBinary(utf8.encode('UDF Compressed Document 4187123'), 'text/plain', precision: 800);
const expected =
'61 8E 14 D9 19 4E D6 02 12 C3 30 A7 BB 5F C7 17 6D AE 9A 56 7C A8 2A 23 1F 96 75 ED 53 10 EC E8 F2 60 14 24 D0 C8 BC 55 3D C0 70 F7 5E 86 38 1A 0B CB 55 9C B2 87 81 27 FF 3C EC E2 F0 90 A0 00';
expect(hexPrintBytes(udfTypedBuffer), expected);
});

test('udf800 printBase32 800 does use max precision 440.', () {
var udfTypedBuffer = UDF.dataToUDFBinary(
utf8.encode('UDF Compressed Document 4187123'), 'text/plain',
var udfTypedBuffer = UDF.dataToUDFBinary(utf8.encode('UDF Compressed Document 4187123'), 'text/plain',
precision: 800, digestAlgorithm: DigestAlgorithm.SHA2_512);
// 440 bits
const expectedFull =
Expand All @@ -97,13 +81,11 @@ void main() {
});

test('udf125 printBase32 800 does use max precision 440.', () {
var udfTypedBuffer = UDF.dataToUDFBinary(
utf8.encode('UDF Compressed Document 4187123'), 'text/plain',
var udfTypedBuffer = UDF.dataToUDFBinary(utf8.encode('UDF Compressed Document 4187123'), 'text/plain',
precision: 200, digestAlgorithm: DigestAlgorithm.SHA2_512);

const expectedShort = 'MGHB-JWIZ-J3LA-EEWD-GCT3-WX6H-C5W2';
var presentationShort =
UDF.printBase32(udfTypedBuffer, charsPerBlock: 4, precision: 125);
var presentationShort = UDF.printBase32(udfTypedBuffer, charsPerBlock: 4, precision: 125);
expect(presentationShort, expectedShort);
});

Expand All @@ -124,8 +106,7 @@ void main() {
var digest = UDF.dataToUDFBinary(data, 'phone');
var udf5PerBlock = UDF.printBase32(digest, precision: 125);
expect(udf5PerBlock, 'MCITH-W7U5A-KUJLL-F44ZK-QXF4Q');
var udf4PerBlock =
UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
var udf4PerBlock = UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
expect(udf4PerBlock, 'MCIT-HW7U-5AKU-JLLF-44ZK-QXF4-QKHJ');
});

Expand All @@ -134,8 +115,7 @@ void main() {
var digest = UDF.dataToUDFBinary(data, 'email');
var udf5PerBlock = UDF.printBase32(digest, precision: 125);
expect(udf5PerBlock, 'MDG3B-QLTSK-Y2DAR-3EIAH-2GI3L');
var udf4PerBlock =
UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
var udf4PerBlock = UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
expect(udf4PerBlock, 'MDG3-BQLT-SKY2-DAR3-EIAH-2GI3-LZHZ');
});

Expand All @@ -144,8 +124,7 @@ void main() {
var digest = UDF.dataToUDFBinary(data, 'iban');
var udf5PerBlock = UDF.printBase32(digest, precision: 125);
expect(udf5PerBlock, 'MCDNU-FPD5R-6TGB3-RSP2K-X5RY3');
var udf4PerBlock =
UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
var udf4PerBlock = UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
expect(udf4PerBlock, 'MCDN-UFPD-5R6T-GB3R-SP2K-X5RY-35UC');
});

Expand All @@ -155,8 +134,7 @@ void main() {
var digest = UDF.dataToUDFBinary(data, 'uuid');
var udf5PerBlock = UDF.printBase32(digest, precision: 125);
expect(udf5PerBlock, 'MAYNJ-MUEGX-IX2ME-4SBLS-IMNAQ');
var udf4PerBlock =
UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
var udf4PerBlock = UDF.printBase32(digest, charsPerBlock: 4, precision: 125);
expect(udf4PerBlock, 'MAYN-JMUE-GXIX-2ME4-SBLS-IMNA-QEY6');
});
});
Expand Down