diff --git a/googleapis_auth/CHANGELOG.md b/googleapis_auth/CHANGELOG.md index 06fcb3fc6..7a0888989 100644 --- a/googleapis_auth/CHANGELOG.md +++ b/googleapis_auth/CHANGELOG.md @@ -1,3 +1,5 @@ +## 2.2.1-wip + ## 2.2.0 - Added `quotaProject` support to existing credentials classes diff --git a/googleapis_auth/lib/src/crypto/asn1.dart b/googleapis_auth/lib/src/crypto/asn1.dart index 04d7892ba..6169a3e6b 100644 --- a/googleapis_auth/lib/src/crypto/asn1.dart +++ b/googleapis_auth/lib/src/crypto/asn1.dart @@ -8,7 +8,7 @@ import 'dart:typed_data'; import 'package:meta/meta.dart'; -import 'rsa.dart'; +import 'rsa.dart' as rsa; // ignore: avoid_classes_with_only_static_members abstract final class ASN1Parser { @@ -91,7 +91,7 @@ abstract final class ASN1Parser { switch (tag) { case integerTag: final size = readEncodedLength(); - return ASN1Integer._(RSAAlgorithm.bytes2BigInt(readBytes(size))); + return ASN1Integer._(rsa.bytes2BigInt(readBytes(size))); case octetStringTag: final size = readEncodedLength(); return ASN1OctetString._(readBytes(size)); diff --git a/googleapis_auth/lib/src/crypto/rsa.dart b/googleapis_auth/lib/src/crypto/rsa.dart index 571a010ef..160f92043 100644 --- a/googleapis_auth/lib/src/crypto/rsa.dart +++ b/googleapis_auth/lib/src/crypto/rsa.dart @@ -9,6 +9,8 @@ import 'dart:typed_data'; +import 'package:meta/meta.dart'; + /// Represents integers obtained while creating a Public/Private key pair. final class RSAPrivateKey { /// First prime number. @@ -50,57 +52,52 @@ final class RSAPrivateKey { ); } -/// Provides a [rawSign] method for signing messages with a [RSAPrivateKey]. -// ignore: avoid_classes_with_only_static_members -abstract final class RSAAlgorithm { - /// Performs the private key operation (signing) on [bytes] with the private - /// [key]. - /// - /// Others who have access to the public key will be able to verify this - /// the result. - /// - /// The [intendedLength] argument specifies the number of bytes in which the - /// result should be encoded. Zero bytes will be used for padding. - static Uint8List rawSign( - RSAPrivateKey key, - List bytes, - int intendedLength, - ) { - final message = bytes2BigInt(bytes); - final encryptedMessage = _encryptInteger(key, message); - return integer2Bytes(encryptedMessage, intendedLength); - } +/// Performs the private key operation (signing) on [bytes] with the private +/// [key]. +/// +/// Others who have access to the public key will be able to verify this +/// the result. +/// +/// The [intendedLength] argument specifies the number of bytes in which the +/// result should be encoded. Zero bytes will be used for padding. +@internal +Uint8List rawSign(RSAPrivateKey key, List bytes, int intendedLength) { + final message = bytes2BigInt(bytes); + final encryptedMessage = _encryptInteger(key, message); + return integer2Bytes(encryptedMessage, intendedLength); +} - static BigInt _encryptInteger(RSAPrivateKey key, BigInt x) { - // The following is equivalent to `(x % key.n).modPow(key.d, key.n)` but is - // much more efficient. It exploits the fact that we have dmp1/dmq1. - var xp = (x % key.p).modPow(key.dmp1, key.p); - final xq = (x % key.q).modPow(key.dmq1, key.q); - while (xp < xq) { - xp += key.p; - } - return ((((xp - xq) * key.coeff) % key.p) * key.q) + xq; +BigInt _encryptInteger(RSAPrivateKey key, BigInt x) { + // The following is equivalent to `(x % key.n).modPow(key.d, key.n)` but is + // much more efficient. It exploits the fact that we have dmp1/dmq1. + var xp = (x % key.p).modPow(key.dmp1, key.p); + final xq = (x % key.q).modPow(key.dmq1, key.q); + while (xp < xq) { + xp += key.p; } + return ((((xp - xq) * key.coeff) % key.p) * key.q) + xq; +} - static BigInt bytes2BigInt(List bytes) { - var number = BigInt.zero; - for (var i = 0; i < bytes.length; i++) { - number = (number << 8) | BigInt.from(bytes[i]); - } - return number; +@internal +BigInt bytes2BigInt(List bytes) { + var number = BigInt.zero; + for (var i = 0; i < bytes.length; i++) { + number = (number << 8) | BigInt.from(bytes[i]); } + return number; +} - static Uint8List integer2Bytes(BigInt integer, int intendedLength) { - if (integer < BigInt.one) { - throw ArgumentError('Only positive integers are supported.'); - } - final bytes = Uint8List(intendedLength); - for (var i = bytes.length - 1; i >= 0; i--) { - bytes[i] = (integer & _bigIntFF).toInt(); - integer >>= 8; - } - return bytes; +@visibleForTesting +Uint8List integer2Bytes(BigInt integer, int intendedLength) { + if (integer < BigInt.one) { + throw ArgumentError('Only positive integers are supported.'); + } + final bytes = Uint8List(intendedLength); + for (var i = bytes.length - 1; i >= 0; i--) { + bytes[i] = (integer & _bigIntFF).toInt(); + integer >>= 8; } + return bytes; } final _bigIntFF = BigInt.from(0xff); diff --git a/googleapis_auth/lib/src/crypto/rsa_sign.dart b/googleapis_auth/lib/src/crypto/rsa_sign.dart index dc2654ca7..77ca54cea 100644 --- a/googleapis_auth/lib/src/crypto/rsa_sign.dart +++ b/googleapis_auth/lib/src/crypto/rsa_sign.dart @@ -7,13 +7,15 @@ import 'dart:typed_data'; import 'package:crypto/crypto.dart'; +import 'package:meta/meta.dart'; -import 'rsa.dart'; +import 'rsa.dart' as rsa; /// Used for signing messages with a private RSA key. /// /// The implemented algorithm can be seen in /// RFC 3447, Section 9.2 EMSA-PKCS1-v1_5. +@internal final class RS256Signer { // DigestInfo :== SEQUENCE { // digestAlgorithm AlgorithmIdentifier, @@ -53,7 +55,7 @@ final class RS256Signer { 0x20, ]; - final RSAPrivateKey _rsaKey; + final rsa.RSAPrivateKey _rsaKey; RS256Signer(this._rsaKey); @@ -74,6 +76,6 @@ final class RS256Signer { offset += _rsaSha256DigestInfoPrefix.length; block.setAll(offset, digest); - return RSAAlgorithm.rawSign(_rsaKey, block, modulusLen); + return rsa.rawSign(_rsaKey, block, modulusLen); } } diff --git a/googleapis_auth/pubspec.yaml b/googleapis_auth/pubspec.yaml index aa9dd4af7..dc29e5c76 100644 --- a/googleapis_auth/pubspec.yaml +++ b/googleapis_auth/pubspec.yaml @@ -1,5 +1,5 @@ name: googleapis_auth -version: 2.2.0 +version: 2.2.1-wip description: Obtain Access credentials for Google services using OAuth 2.0 repository: https://github.com/google/googleapis.dart/tree/master/googleapis_auth diff --git a/googleapis_auth/test/crypto/rsa_test.dart b/googleapis_auth/test/crypto/rsa_test.dart index 7c0df2f0e..76916cbff 100644 --- a/googleapis_auth/test/crypto/rsa_test.dart +++ b/googleapis_auth/test/crypto/rsa_test.dart @@ -4,7 +4,7 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd -import 'package:googleapis_auth/src/crypto/rsa.dart'; +import 'package:googleapis_auth/src/crypto/rsa.dart' as rsa; import 'package:test/test.dart'; import '../test_utils.dart'; @@ -14,19 +14,9 @@ final _bigNumber = BigInt.parse('20000000000000000', radix: 16); void main() { test('integer2Bytes converts BigInt to byte list', () { - expect(RSAAlgorithm.integer2Bytes(BigInt.one, 1), [1]); - expect(RSAAlgorithm.integer2Bytes(_bigNumber, 9), [ - 2, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]); - expect(RSAAlgorithm.integer2Bytes(_bigNumber, 12), [ + expect(rsa.integer2Bytes(BigInt.one, 1), [1]); + expect(rsa.integer2Bytes(_bigNumber, 9), [2, 0, 0, 0, 0, 0, 0, 0, 0]); + expect(rsa.integer2Bytes(_bigNumber, 12), [ 0, 0, 0, @@ -40,15 +30,12 @@ void main() { 0, 0, ]); - expect( - () => RSAAlgorithm.integer2Bytes(BigInt.zero, 1), - throwsArgumentError, - ); + expect(() => rsa.integer2Bytes(BigInt.zero, 1), throwsArgumentError); }); test('bytes2BigInt converts byte list to BigInt', () { - expect(RSAAlgorithm.bytes2BigInt([1]), BigInt.one); - expect(RSAAlgorithm.bytes2BigInt([2, 0, 0, 0, 0, 0, 0, 0, 0]), _bigNumber); + expect(rsa.bytes2BigInt([1]), BigInt.one); + expect(rsa.bytes2BigInt([2, 0, 0, 0, 0, 0, 0, 0, 0]), _bigNumber); }); test('rawSign performs raw RSA signing', () { @@ -72,7 +59,7 @@ void main() { 26, 217, 230, 133, 217, 76, ]; expect( - RSAAlgorithm.rawSign(testPrivateKey, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 256), + rsa.rawSign(testPrivateKey, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 256), encryptedData, ); });