Ephenodrom / Dart-Basic-Utils

A dart package for many helper methods fitting common situations
MIT License
364 stars 77 forks source link

Exception (type 'ASN1Object' is not a subtype of type 'ASN1Sequence' in type cast) #93

Closed ArturKozak closed 1 year ago

ArturKozak commented 1 year ago

I am trying to get the ECPrivateKey key, but the following error has occurred Exception has occurred. _CastError (type 'ASN1Object' is not a subtype of type 'ASN1Sequence' in type cast) image

Here is my code:

final textBytes = utf8.encode(text) as Uint8List;

    final rawKey = '''
-----BEGIN PRIVATE KEY-----
$privateKey 
-----END PRIVATE KEY-----
''';

    final bytes = util.CryptoUtils.getBytesFromPEMString(rawKey);

    final isPkcs8 = rawKey.startsWith(util.CryptoUtils.BEGIN_PRIVATE_KEY);

    final key = util.CryptoUtils.ecPrivateKeyFromDerBytes(
      bytes,
      pkcs8: isPkcs8,
    );

What am I doing wrong, is there a problem with the package?

Ephenodrom commented 1 year ago

@ArturKozak Can you provide the a private key for testing, that was generated in the same way as the one that has the problem ? I claim that everything should actually work, since enough unit tests are available with examples from OpenSSL.

You can also try to use the other method to read the PEM string directly :

CryptoUtils.ecPrivateKeyFromPem(pem);

You can find an example private key here : https://github.com/Ephenodrom/Dart-Basic-Utils/blob/master/test/crypto_utils_test.dart#LL81C7-L81C24

ArturKozak commented 1 year ago

@Ephenodrom Thanks for the answer, after looking at the example you provided, I realised that I don't exactly have a private key, it's already decoded. Correct me if I'm wrong. 0lVsNIW29NNCaJXYKERNA8atxkqYOPKEgmr+BnA7NlQ3VVvgVGGhWR3c8TTiXY5nD/GeUrfZPl5sW3XX3eKabqs6+uSGZPElMDvJzYBtAq5FrxxkusSjhs8kpFA/dUgBp3aLvq5Cbvi48iQ+47Sy3mU65eICIDJOoNvkVKnqoJyPtQ05IzQyCqWiNFZY5JsEOgeVqb/7C9nw3JvNfKZjTvCS0nb2dEXYhfiORjoN1/ItwuCzfpQwQjEHEM3UJg8Ve7e+6MAktLuI+fErigkYEVGOdBEQlO9k2J4fstRrG2bJsPCuZ2scnxqWnM3AYxY9RNom3QKctU1d4RDydMz+3GsJXy5riE0OZxNtKBoVh54Qf51ot+3HNQgPW/QITyTpRE1EFJbaWqLT8Kw= Can I merge it somehow with ECPrivateKey for

final sig = util.CryptoUtils.ecSign(
      key, <= here
      bytes,
      algorithmName: 'SHA-384/ECDSA',
    );
Ephenodrom commented 1 year ago

@ArturKozak That seems to be NO KEY at all. What do you want to achieve at the end ?

ArturKozak commented 1 year ago

@Ephenodrom This is all necessary to get a signature to encode the text in the chat. I'll attach a description of the backend that needs to be implemented in Dart.


For signing the subject (e.g. chat message, document or any activity-related data), we use ECDSA with SHA-384.

export const sign = (key: CryptoKey, subject: ArrayBuffer) =>
  crypto.subtle.sign(
    {
      name: "ECDSA",
      hash: { name: "SHA-384" }
    },
    key,
    subject
  )
const encryptText = useCallback(
  async (text: string) => {
    const session = await getLatestSession()
    if (!session) {
      throw new Error("Missing session, unable to encrypt text.")
    }

    const encodedText = textEncoder.encode(text)
    const iv = generateNonce()

    const signature =
      signingKeyPair && supportsFeature("EncryptedContentSigning")
        ? await sign(signingKeyPair.privateKey, encodedText)
        : undefined

    const encryptedText = await encryptAes(session.secret, encodedText, iv, signature)

    return {
      ciphertext: toBase64(encryptedText),
      iv: toBase64(iv),
      secretVersion: session.version,
      signature: signature ? toBase64(signature) : undefined,
      signingKeyVersion: signingKeyPair?.version,
      userId
    } as Domain.EncryptedContent
  },
  [getLatestSession, signingKeyPair, supportsFeature, userId]
)

I get this key from the server privateKeyJwk: string = 0lVsNIW29NNCaJXYKERNA8atxkqYOPKEgmr+BnA7NlQ3VVvgVGGhWR3c8TTiXY5nD/GeUrfZPl5sW3XX3eKabqs6+uSGZPElMDvJzYBtAq5FrxxkusSjhs8kpFA/dUgBp3aLvq5Cbvi48iQ+47Sy3mU65eICIDJOoNvkVKnqoJyPtQ05IzQyCqWiNFZY5JsEOgeVqb/7C9nw3JvNfKZjTvCS0nb2dEXYhfiORjoN1/ItwuCzfpQwQjEHEM3UJg8Ve7e+6MAktLuI+fErigkYEVGOdBEQlO9k2J4fstRrG2bJsPCuZ2scnxqWnM3AYxY9RNom3QKctU1d4RDydMz+3GsJXy5riE0OZxNtKBoVh54Qf51ot+3HNQgPW/QITyTpRE1EFJbaWqLT8Kw=

This is my implementation with this package:

static Future<List<int>> _singContent({
    required Uint8List bytes,
    required String privateKey,
  }) async {
    final rawKey = '''
-----BEGIN PRIVATE KEY-----
$privateKey  <== I think this key has already been decoded.
-----END PRIVATE KEY-----
''';

    final bytes = util.CryptoUtils.getBytesFromPEMString(rawKey);

    final isPkcs8 = rawKey.startsWith(util.CryptoUtils.BEGIN_PRIVATE_KEY);

    final key = util.CryptoUtils.ecPrivateKeyFromDerBytes(
      bytes,
      pkcs8: isPkcs8,
    );

    final sig = util.CryptoUtils.ecSign(
      key,
      bytes,
      algorithmName: 'SHA-384/ECDSA',
    );

    final signature = util.CryptoUtils.ecSignatureToBase64(sig);

    return utf8.encode(signature);
  }
Ephenodrom commented 1 year ago

@ArturKozak

I'm sorry, but in this case I can't help you here. To me it looks like you are getting a JWK from your backend. But this is not in PEM format. Therefore this package does not help you. I would suggest you try e.g. the following package: https://pub.dev/packages/jose

This supports JWK and it should be possible to use it with the provided JWK. I will close this issue.