首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将QR解码解决方案从Python转换为C# (EU )

将QR解码解决方案从Python转换为C# (EU )
EN

Stack Overflow用户
提问于 2021-08-19 11:23:15
回答 4查看 4.6K关注 0票数 1

我正在尝试将此Python代码转换为C# (理想情况下是.NET核心)。来源

我的目标是将QR输入字符串转换为包含json中数据的另一个字符串。请参阅提供的链接。

代码语言:javascript
复制
#! /usr/bin/env python3
import json
import sys
import zlib
 
import base45
import cbor2
from cose.messages import CoseMessage
 
payload = sys.argv[1][4:]
print("decoding payload: "+ payload)
 
# decode Base45 (remove HC1: prefix)
decoded = base45.b45decode(payload)
 
# decompress using zlib
decompressed = zlib.decompress(decoded)
# decode COSE message (no signature verification done)
cose = CoseMessage.decode(decompressed)
# decode the CBOR encoded payload and print as json
print(json.dumps(cbor2.loads(cose.payload), indent=2))

我找不到任何用于NuGet Zlib的包,这将正确工作。所以,在base45解码之后,我被直接卡住了。谢谢你的建议。

代码语言:javascript
复制
using System.Text; //Rystem.Text.Base45 NuGet
    
var removedHeader = testQrData.Substring(4);
var decoded = removedHeader.FromBase45();
byte[] rawBytes = Encoding.ASCII.GetBytes(decoded);

链接可能有助于进一步的研究。

解码方案

EN

回答 4

Stack Overflow用户

发布于 2021-09-22 07:08:33

代码语言:javascript
复制
IBarcodeReader reader = new BarcodeReader();//using Zxing
var barcodeBitmap = (Bitmap)Bitmap.FromFile("qrcode.png");

var barcodeReader = new BarcodeReader();

var qrcontent = barcodeReader.Decode(barcodeBitmap).Text;

var qrmessage = qrcontent.Substring(4);//remove first 4 chars

byte[] decodedBase45 = Base45Encoding.Decode(qrmessage);//using base45 lib
var cose = ZlibStream.UncompressBuffer(decodedBase45);//using zlib or similar

var decrypted = Message.DecodeFromBytes(cose).GetContent(); //using COSE
CBORObject cbor = CBORObject.DecodeFromBytes(decrypted);    //using Peter.O.. CBOR

var jsonDecoded = cbor.ToJSONString(); //or deserialize it to custom class
票数 3
EN

Stack Overflow用户

发布于 2021-08-19 11:31:29

我过去曾使用ZXing库来解码和创建QR代码:

https://github.com/micjahn/ZXing.Net

您也可以尝试:https://github.com/codebude/QRCoder

下面是他们的github页面中的一个快速ZXing示例:

代码语言:javascript
复制
// create a barcode reader instance
IBarcodeReader reader = new BarcodeReader();
// load a bitmap
var barcodeBitmap = (Bitmap)Image.LoadFrom("C:\\sample-barcode-image.png");
// detect and decode the barcode inside the bitmap
var result = reader.Decode(barcodeBitmap);
// do something with the result
if (result != null)
{
   txtDecoderType.Text = result.BarcodeFormat.ToString();
   txtDecoderContent.Text = result.Text;
}

此示例读取QR代码映像。

我不知道您的输入是什么,但我假设它也是二进制格式的图像,所以您可能需要四处播放才能让它正常工作。

票数 0
EN

Stack Overflow用户

发布于 2021-11-08 08:54:15

这个解决方案对我有效。

代码语言:javascript
复制
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using System;
using System.IO;
using Com.AugustCellars.COSE;
using PeterO.Cbor;
using Newtonsoft.Json;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Collections.Generic;

namespace DGCVerification.Services {
  public class DGCVerificationService: IDGCVerificationService {
    private readonly string _certificatePrefix = "HC1:";

private readonly ILogger < DGCVerificationService > _logger;

public DGCVerificationService(ILogger < DGCVerificationService > logger) {
  _logger = logger;
}

private bool TryTrimPrefix(string certificateString, out string result) {
  if (!certificateString.StartsWith(_certificatePrefix)) {
    result = null;
    return false;
  }

  result = certificateString.Substring(_certificatePrefix.Length);
  return true;
}

private byte[] DecompressFromZlib(byte[] input) {
  using(var memoryStream = new MemoryStream(input)) {
    using(var decompressionStream = new InflaterInputStream(memoryStream)) {
      using(var resultStream = new MemoryStream()) {
        decompressionStream.CopyTo(resultStream);
        var result = resultStream.ToArray();
        return result;
      }
    }
  }
}

private bool VerifyCoseSignature(Sign1Message coseMessage, string signature) {
  var signatureAsBytes = Convert.FromBase64String(signature);

  var publicKey = OneKey.FromX509(signatureAsBytes);
  var result = coseMessage.Validate(publicKey);

  _logger.LogInformation($"cose message signature {signature} verified as {result}");
  return result;
}

private DGCPayload DecodeAndDeserialize(string certificateString, out Sign1Message coseMessage) {
  coseMessage = null;
  if (!TryTrimPrefix(certificateString, out
      var trimmedPrefixString)) {
    _logger.LogInformation($"certificate {certificateString} didn't have proper prefix {_certificatePrefix}");
    return null;
  }

  var bytesBase256 = Base45Encoding.Decode(trimmedPrefixString);
  _logger.LogInformation($"certificate {certificateString} base45 decoded to  {Convert.ToBase64String(bytesBase256)}");

  var decompressedFromZlib = DecompressFromZlib(bytesBase256);
  _logger.LogDebug($"certificate {certificateString} zlib decompressed to {Convert.ToBase64String(decompressedFromZlib)}");

  coseMessage = Message.DecodeFromBytes(decompressedFromZlib) as Sign1Message;
  var coseMessagePayload = coseMessage.GetContent();
  var cborResult = CBORObject.DecodeFromBytes(coseMessagePayload);
  var jsonResult = cborResult.ToJSONString();
  var result = JsonConvert.DeserializeObject < DGCPayloadCzechVersionRoot > (jsonResult);
  return result.DGCPayloadWrap.DGCPayload;
}

private bool IsNotExpiredDGC(DGCPayload dGCPayload, UzisData uzisData) {
  var vaccine = dGCPayload.Vaccination?.FirstOrDefault();

  if (vaccine != null) {
    var vaccinationValidityRules = uzisData.DGCValidityCzechRules.Rules
      .FirstOrDefault()
      .PlatnostiVakcinace;

    var rule = vaccinationValidityRules.FirstOrDefault(x => x.VaccineMedicinalProduct == vaccine.Mp) ??
      vaccinationValidityRules.FirstOrDefault(x => x.VaccineMedicinalProduct == null);

    if (!DateTime.TryParse(vaccine.Dt, out
        var vaccinatedOnDate)) {
      _logger.LogError($"couldn't parse date of vaccination for DGC : {JsonConvert.SerializeObject(dGCPayload)}");
      return false;
    }

    var result = DateTime.Now.Date <= vaccinatedOnDate.AddMonths(rule.OdolnostMesicDo);
    return result;
  }

  var test = dGCPayload.Test?.FirstOrDefault();

  if (test != null) {
    var testValidityRule = uzisData.DGCValidityCzechRules.Rules
      .FirstOrDefault()
      .PlatnostiTestu
      .FirstOrDefault(x => x.TypeOfTest == test.Tt);

    if (!DateTime.TryParse(test.Tr, out
        var testedOnDate)) {
      _logger.LogError($"couldn't parse date of test for DGC : {JsonConvert.SerializeObject(dGCPayload)}");
      return false;
    }

    var result = DateTime.Now.Date <= testedOnDate.AddHours(testValidityRule.PlatnostHod);

    return result;
  }

  var recovery = dGCPayload.Recovery?.FirstOrDefault();

  if (recovery != null) {
    if (!DateTime.TryParse(recovery.Du, out
        var recoveryValidUntil)) {
      _logger.LogError($"couldn't parse recovert valid until for DGC : {JsonConvert.SerializeObject(dGCPayload)}");
      return false;
    }

    var result = DateTime.Now.Date <= recoveryValidUntil;
    return result;
  }

  return false;
}

private string GetCountryFromDGC(DGCPayload dGCPayload) {
  var result = dGCPayload.Vaccination?.FirstOrDefault()?.Co ??
    dGCPayload.Test?.FirstOrDefault()?.Co ??
    dGCPayload.Recovery?.FirstOrDefault()?.Co;

  if (result == null) {
    throw new ArgumentException($"couldn't retrieve country from DGC. dgc : {JsonConvert.SerializeObject(dGCPayload)}");
  }

  return result;
}

private List < SignatureCertificate > GetFittingSignatures(DGCPayload dGCPayload, UzisData uzisData) {
  try {
    var country = GetCountryFromDGC(dGCPayload);

    var result = uzisData.NationalCertificateSignatures.SignatureCertificate
      .Where(x => x.Active)
      .Where(x => x.Country == country)
      .Where(x => x.CertificateType == "DSC")
      .ToList();

    return result;
  } catch (Exception e) {
    _logger.LogError(e, $"Filtering signatures from UZIS failed with exception");
    return null;
  }
}

private bool IsProperlySignedDGC(string certificateString, DGCPayload dGCPayload, Sign1Message coseMessage, UzisData uzisData) {
  var fittingSignatures = GetFittingSignatures(dGCPayload, uzisData);
  var result = false;
  foreach(var signature in fittingSignatures) {
    try {
      var signatureVerificationResult = VerifyCoseSignature(coseMessage, signature.RawData);

      _logger.LogInformation($"certificate {certificateString} signature validation against signature {signature} resulted in {signatureVerificationResult}");

      result |= signatureVerificationResult;
    } catch (Exception e) {
      _logger.LogError(e, $"certificate {certificateString} signature validation against signature {signature} failed with exception");
    }
  }

  return result;
}

public bool IsValidDgc(string certificateString, UzisData uzisData, out DGCPayload decodedDGCPayload, out VerificationResult verificationResult) {
  decodedDGCPayload = null;
  Sign1Message coseMessage = null;

  try {
    decodedDGCPayload = DecodeAndDeserialize(certificateString, out coseMessage);

    if (coseMessage == null) {
      _logger.LogInformation($"certificate {certificateString} decoded to null COSE");
      verificationResult = VerificationResult.UnableToDecode;
      return false;
    }
  } catch (Exception e) {
    _logger.LogError(e, $"certificate {certificateString} decoding failed with exception");
    verificationResult = VerificationResult.UnableToDecode;
    return false;
  }

  var isProperlySigned = IsProperlySignedDGC(certificateString, decodedDGCPayload, coseMessage, uzisData);

  if (!isProperlySigned) {
    verificationResult = VerificationResult.InvalidSignature;
    return false;
  }

  var isNotExpired = IsNotExpiredDGC(decodedDGCPayload, uzisData);

  if (!isNotExpired) {
    verificationResult = VerificationResult.Expired;
    return false;
  }

  verificationResult = VerificationResult.Valid;
  return true;
    }
  }
}

和棘手的base45

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DGCVerification
{
public class Base45Encoding
{
    private static readonly Dictionary<byte, char> _encodingTable = new Dictionary<byte, char>
    {
            {0x0,'0'},
            {0x1,'1'},
            {0x2,'2'},
            {0x3,'3'},
            {0x4,'4'},
            {0x5,'5'},
            {0x6,'6'},
            {0x7,'7'},
            {0x8,'8'},
            {0x9,'9'},
            {0xA,'A'},
            {0xB,'B'},
            {0xC,'C'},
            {0xD,'D'},
            {0xE,'E'},
            {0xF,'F'},
            {0x10,'G'},
            {0x11,'H'},
            {0x12,'I'},
            {0x13,'J'},
            {0x14,'K'},
            {0x15,'L'},
            {0x16,'M'},
            {0x17,'N'},
            {0x18,'O'},
            {0x19,'P'},
            {0x1A,'Q'},
            {0x1B,'R'},
            {0x1C,'S'},
            {0x1D,'T'},
            {0x1E,'U'},
            {0x1F,'V'},
            {0x20,'W'},
            {0x21,'X'},
            {0x22,'Y'},
            {0x23,'Z'},
            {0x24,' '},
            {0x25,'$'},
            {0x26,'%'},
            {0x27,'*'},
            {0x28,'+'},
            {0x29,'-'},
            {0x2A,'.'},
            {0x2B,'/'},
            {0x2C,':'},
    };

    private static readonly Dictionary<char, byte> _decodingTable;

    static Base45Encoding()
    {
        _decodingTable = _encodingTable.ToDictionary(x => x.Value, x => x.Key);
    }

    private static List<byte> ToBytesBase45(string charsBase45)
    {
        var result = new List<byte>(charsBase45.Length);
        foreach (var character in charsBase45)
        {
            if (!_decodingTable.TryGetValue(character, out byte asByte))
            {
                throw new FormatException($"input string contains {character} with numeric value {char.GetNumericValue(character)} on index {charsBase45.IndexOf(character)} which is not valid base45 character");
            }
            result.Add(asByte);
        }

        return result;
    }

    private static List<ushort> ToShortsBase10(List<byte> bytesBase45)
    {
        var result = new List<ushort>(bytesBase45.Count);
        ushort num = 0;
        double pow = 0;

        for (int i = 0; i != bytesBase45.Count; ++i, ++pow)
        {
            num += (ushort)(bytesBase45[i] * Math.Pow(45, pow));

            if (pow == 2 || i == (bytesBase45.Count -1))
            {
                result.Add(num);
                num = 0;
                pow = -1;
            }
        }

        return result;
    }

    private static List<byte> ToBytesBase256(List<ushort> shortsBase10, int charBase45Length)
    {
        var result = new List<byte>(shortsBase10.Count);

        for (int i = 0; i != shortsBase10.Count; ++i)
        {
            var num = (byte)(shortsBase10[i] / 256);

            if(!(i == (shortsBase10.Count - 1) 
                && charBase45Length % 3 != 0
                && num == 0))
            {
                result.Add(num);
            }
            result.Add((byte)(shortsBase10[i] % 256));
        }

        return result;
    }

    public static byte[] Decode(string charsBase45)
    {
        if (charsBase45.Length % 3 == 1)
        {
            throw new FormatException("input string does not have correct length. mod 3 == 1. it isnt base45");
        }

        var bytesBase45 = ToBytesBase45(charsBase45);
        var shortsBase10 = ToShortsBase10(bytesBase45);
        var bytesBase256 = ToBytesBase256(shortsBase10, charsBase45.Length);

        return bytesBase256.ToArray();
    }
}
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68846927

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档