123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- using Edge.Core.Processor;
- using Edge.Core.Processor.Dispatcher.Attributes;
- using Edge.Core.UniversalApi;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Logging.Abstractions;
- using ShengJuDesFireEv1CpuCardKeyLoader;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using static ShengJu_CUT100_DES.GroupHandler;
- using static ShengJu_CUT100_DES.MessageEntity.Outgoing.ModifyPredefinedFileKey;
- namespace ClassicCpuCardApp
- {
- [UniversalApi(Name = GenericAlarm.UniversalApiEventName, EventDataType = typeof(GenericAlarm[]), Description = "Fire GenericAlarms to AlarmBar for attracting users.")]
- [UniversalApi(Name = OnCardTapEventName, EventDataType = typeof(object), Description = "Fired once a DesFire EV1 card detected by module and card UID is read")]
- [UniversalApi(Name = OnCardReaderModuleStateChangeEventName, EventDataType = typeof(CardReaderModule), Description = "Fired once card reader module state changed")]
- [MetaPartsDescriptor(
- "lang-zh-cn:CPU卡读写卡应用lang-en-us:CPU Card Read&Write App",
- "lang-zh-cn:CPU卡读写卡应用,用于管理多个 盛炬CUT100_DES 感应卡读写卡模块lang-en-us:CPU卡读写卡应用,用于管理多个 盛炬CUT100_DES 感应卡读写卡模块",
- new[] { "lang-zh-cn:支付终端lang-en-us:Terminal" })]
- public class App : IAppProcessor
- {
- private AppConfigV1 appConfig;
- private LocalNetworkMacBasedEncryptionKeyLoader keyLoader;
- private IEnumerable<ShengJu_CUT100_DES.GroupHandler> cardReaderDeviceHandlers;
- private IEnumerable<CardReaderModule> cardReaderModules;
- private ILogger logger = NullLogger.Instance;
- private IServiceProvider services;
- public const string OnCardTapEventName = "OnCardTap";
- public const string OnCardReaderModuleStateChangeEventName = "OnCardReaderModuleStateChange";
- public string MetaConfigName { get; set; }
- public IEnumerable<CardReaderModule> CardReaderModuels => this.cardReaderModules;
- public class AppConfigV1
- {
- public EncryptedBase64KeySet EncryptedBase64KeySet { get; set; }
- }
- private byte[] blankCardDefaultRootKey;
- private byte[] newRootKey;
- private byte[] file1DefaultReadKey;
- private byte[] file1DefaultWriteKey;
- public App(AppConfigV1 appConfig, IServiceProvider services)
- {
- this.appConfig = appConfig;
- this.services = services;
- var loggerFactory = services.GetRequiredService<ILoggerFactory>();
- this.logger = loggerFactory.CreateLogger("DynamicPrivate_ClassicCpuCardApp");
- this.keyLoader = new LocalNetworkMacBasedEncryptionKeyLoader(this.logger);
- }
- public void Init(IEnumerable<IProcessor> processors)
- {
- this.cardReaderDeviceHandlers = processors.WithHandlerOrApp<ShengJu_CUT100_DES.GroupHandler>()
- .SelectHandlerOrAppThenCast<ShengJu_CUT100_DES.GroupHandler>();
- if (this.cardReaderDeviceHandlers == null || !this.cardReaderDeviceHandlers.Any())
- throw new InvalidOperationException("当前 APP 的运行必须要求系统中配置一个或者多个“ShengJu_CUT100_DES设备驱动” ,但当前没有获取到,请配置并启用相应设备驱动后重试");
- if (this.cardReaderDeviceHandlers.SelectMany(dh => dh.CardReaderModuels).GroupBy(b => new { b.UnderlyingCommunicatorIdentity, b.PhysicalAddress }).Any(g => g.Count() >= 2))
- throw new ArgumentException("发现多个 'ShengJu_CUT100_DES设备驱动' 配置中有重复的硬件地址值,请检查相应的设备驱动以确保同一通讯链路上硬件地址唯一,再重试 ");
- if (this.cardReaderDeviceHandlers.SelectMany(dh => dh.CardReaderModuels).GroupBy(b => b.Name).Any(g => g.Count() >= 2))
- throw new ArgumentException("发现多个 'ShengJu_CUT100_DES设备驱动' 配置中有重复的读卡器名称(Name),请检查相应的设备驱动以确保全局名称唯一,再重试 ");
- foreach (var dh in this.cardReaderDeviceHandlers)
- {
- dh.OnModuleStateChange += async (s, a) =>
- {
- var universalApiHub = this.services.GetRequiredService<UniversalApiHub>();
- await universalApiHub?.FireEvent(this, OnCardReaderModuleStateChangeEventName, dh);
- };
- }
- foreach (var dh in this.cardReaderDeviceHandlers)
- {
- dh.OnCardTap += async (s, a) =>
- {
- var universalApiHub = this.services.GetRequiredService<UniversalApiHub>();
- await universalApiHub?.FireEvent(this, OnCardTapEventName, a);
- };
- }
- this.cardReaderModules = this.cardReaderDeviceHandlers.SelectMany(dh => dh.CardReaderModuels);
- }
- [UniversalApi(Description = "Get all available card reader moduel names")]
- public async Task<IEnumerable<CardReaderModule>> GetCardReaderModuleNames()
- {
- return this.cardReaderDeviceHandlers.SelectMany(dh => dh.CardReaderModuels);
- }
- [UniversalApi(
- Description = "Set new RootKey to card, re-build(clear, re-create and set file keys) the files and blocks(4 files, and 4 blocks with 32 bytes for each file).</br>" +
- "All the new keys are <b>decrypted</b> from app's config values.</br>" +
- "Leave oldRootKeyBytes to <b>null</b> will use the key decrypted from app's config values.</br>" +
- "For most DesFireEV1 Cards, the <b>factory-reset</b> root and file read&write keys are 16 bytes of 0</br>",
- InputParametersExampleJson = "[\"desktopReader0\",[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]")]
- public async Task<IEnumerable<CardOperationResult>> FormatCard(string cardReaderModuleName, int[] oldRootKeyBytes)
- {
- var keySet = this.keyLoader.Get(this.appConfig.EncryptedBase64KeySet);
- if (oldRootKeyBytes == null)
- oldRootKeyBytes = keySet.RootKey.Select(b => (int)b).ToArray();
- var formatBatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.FormatCardByResetToNewRootKeyAndBuildDefaultFileStructures(cardReaderModuleName,
- oldRootKeyBytes.Select(i => (byte)i).ToArray(),
- keySet.RootKey));
- var formatResultsRaw = await Task.WhenAll(formatBatchOperationTasks);
- var formatResults = formatResultsRaw.SelectMany(r => r);
- if (formatResults.Any(r => r.OverallResultCode != 200))
- return formatResults;
-
-
- byte[] oldFileKeyBytes = Enumerable.Repeat(0, 16).Select(i => (byte)i).ToArray();
-
- byte[] fileKey = keySet.文件1读密钥;
- var modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件1读密钥, oldFileKeyBytes, fileKey));
- var modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- var modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
- fileKey = keySet.文件1读写密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件1读写密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
-
- fileKey = keySet.文件2读密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件2读密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
- fileKey = keySet.文件2读写密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件2读写密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
-
- fileKey = keySet.文件3读密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件3读密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
- fileKey = keySet.文件3读写密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件3读写密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
-
- fileKey = keySet.文件4读密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件4读密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
- fileKey = keySet.文件4读写密钥;
- modifyPredefinedFileKeybatchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName,
- PredefinedFileKeyTypeEnum.文件4读写密钥, oldFileKeyBytes, fileKey));
- modifyPredefinedFileKeyResultsRaw = await Task.WhenAll(modifyPredefinedFileKeybatchOperationTasks);
- modifyPredefinedFileKeyResults = modifyPredefinedFileKeyResultsRaw.SelectMany(r => r);
- if (modifyPredefinedFileKeyResults.Any(r => r.OverallResultCode != 200))
- return modifyPredefinedFileKeyResults;
- return modifyPredefinedFileKeyResults;
- }
- [UniversalApi(
- Description = "Modify the read or write keys for the specified file, the new key is decrypted from app's config values, " +
- "make sure adding those enctryption keys from config UI first.",
- InputParametersExampleJson = "[\"desktopReader0\",\"文件1读密钥\",[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]")]
- public async Task<CardOperationResult[]> ModifyPredefinedFileKey(string cardReaderModuleName, PredefinedFileKeyTypeEnum fileKeyType, int[] oldKeyBytes)
- {
- var keySet = this.keyLoader.Get(this.appConfig.EncryptedBase64KeySet);
- byte[] newKey = null;
- if (fileKeyType == PredefinedFileKeyTypeEnum.根密钥)
- newKey = keySet.文件1读密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件1读密钥)
- newKey = keySet.文件1读密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件1读写密钥)
- newKey = keySet.文件1读写密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件2读密钥)
- newKey = keySet.文件2读密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件2读写密钥)
- newKey = keySet.文件2读写密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件3读密钥)
- newKey = keySet.文件3读密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件3读写密钥)
- newKey = keySet.文件3读写密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件4读密钥)
- newKey = keySet.文件4读密钥;
- if (fileKeyType == PredefinedFileKeyTypeEnum.文件4读写密钥)
- newKey = keySet.文件4读写密钥;
- if ((oldKeyBytes?.Length ?? 0) != 16)
- throw new ArgumentOutOfRangeException(nameof(oldKeyBytes));
- var batchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ModifyPredefinedFileKey(cardReaderModuleName, fileKeyType, oldKeyBytes.Select(i => (byte)i).ToArray(), newKey));
- var results = await Task.WhenAll(batchOperationTasks);
- List<CardOperationResult> final = new List<CardOperationResult>();
- foreach (var r in results)
- final.AddRange(r);
- return final.ToArray();
- }
- [UniversalApi(Description = "Write a 32 bytes content to card by specify the destination fileId and blockAddress, " +
- "the default fileId range is from 1 to 4, with 4 blocks in a file with address from 1-4, each block with size 32 bytes.",
- InputParametersExampleJson = "[\"desktopReader0\",1,1,[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]]")]
- public async Task<CardOperationResult[]> WriteCardWithRawData(string cardReaderModuleName, byte fileId, byte blockAddress, int[] dataBytes)
- {
- var keySet = this.keyLoader.Get(this.appConfig.EncryptedBase64KeySet);
- byte[] writeKey = null;
- if (fileId == 1)
- writeKey = keySet.文件1读写密钥;
- else if (fileId == 2)
- writeKey = keySet.文件2读写密钥;
- else if (fileId == 3)
- writeKey = keySet.文件3读写密钥;
- else if (fileId == 4)
- writeKey = keySet.文件4读写密钥;
- else
- throw new ArgumentOutOfRangeException(nameof(fileId));
- if (blockAddress == 0 || blockAddress > 4)
- throw new ArgumentOutOfRangeException(nameof(blockAddress));
- if ((dataBytes?.Length ?? 0) != 32)
- throw new ArgumentOutOfRangeException(nameof(dataBytes));
- var batchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.WriteCard(cardReaderModuleName, fileId, blockAddress, dataBytes.Select(i => (byte)i).ToArray(), writeKey));
- var results = await Task.WhenAll(batchOperationTasks);
- List<CardOperationResult> final = new List<CardOperationResult>();
- foreach (var r in results)
- final.AddRange(r);
- return final.ToArray();
- }
- [UniversalApi(Description = "Write a text content (which must have Utf8 bytes length <=32) to card by specify the destination fileId and blockAddress, " +
- "the default fileId range is from 1 to 4, with 4 blocks in a file with address from 1-4, each block with size 32 bytes.",
- InputParametersExampleJson = "[\"desktopReader0\",1,1,\"UserNameIsShao\"]")]
- public async Task<CardOperationResult[]> WriteCardWithTextData(string cardReaderModuleName, byte fileId, byte blockAddress, string plainTextData)
- {
- var keySet = this.keyLoader.Get(this.appConfig.EncryptedBase64KeySet);
- byte[] writeKey = null;
- if (fileId == 1)
- writeKey = keySet.文件1读写密钥;
- else if (fileId == 2)
- writeKey = keySet.文件2读写密钥;
- else if (fileId == 3)
- writeKey = keySet.文件3读写密钥;
- else if (fileId == 4)
- writeKey = keySet.文件4读写密钥;
- else
- throw new ArgumentOutOfRangeException(nameof(fileId));
- if (blockAddress == 0 || blockAddress > 4)
- throw new ArgumentOutOfRangeException(nameof(blockAddress));
- var dataBytes = Encoding.UTF8.GetBytes(plainTextData);
- if ((dataBytes?.Length ?? 0) > 32)
- throw new ArgumentOutOfRangeException(nameof(dataBytes));
- char paddingRightChar = ' ';
- dataBytes = dataBytes.Concat(Enumerable.Repeat((byte)paddingRightChar, 32 - dataBytes.Length)).ToArray();
- var batchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.WriteCard(cardReaderModuleName, fileId, blockAddress, dataBytes, writeKey));
- var results = await Task.WhenAll(batchOperationTasks);
- List<CardOperationResult> final = new List<CardOperationResult>();
- foreach (var r in results)
- final.AddRange(r);
- return final.ToArray();
- }
- [UniversalApi(Description = "Read a 32 bytes content from card by specify the source fileId and blockAddress, " +
- "the default fileId range is from 1 to 4, with 4 blocks in a file with address from 1-4, each block with size 32 bytes.",
- InputParametersExampleJson = "[\"desktopReader0\",1,1]")]
- public async Task<CardOperationResult[]> ReadCardContent(string cardReaderModuleName, byte fileId, byte blockAddress)
- {
- var keySet = this.keyLoader.Get(this.appConfig.EncryptedBase64KeySet);
- byte[] readKey = null;
- if (fileId == 1)
- readKey = keySet.文件1读密钥;
- else if (fileId == 2)
- readKey = keySet.文件2读密钥;
- else if (fileId == 3)
- readKey = keySet.文件3读密钥;
- else if (fileId == 4)
- readKey = keySet.文件4读密钥;
- else
- throw new ArgumentOutOfRangeException(nameof(fileId));
- if (blockAddress == 0 || blockAddress > 4)
- throw new ArgumentOutOfRangeException(nameof(blockAddress));
- var batchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ReadCard(cardReaderModuleName, fileId, blockAddress, readKey));
- var results = await Task.WhenAll(batchOperationTasks);
- List<CardOperationResult> final = new List<CardOperationResult>();
- foreach (var r in results)
- final.AddRange(r);
- return final.ToArray();
- }
- [UniversalApi(Description = "Read card open ID(unsafe) from any card tapped on card reader module(s).",
- InputParametersExampleJson = "[\"desktopReader0\"]")]
- public async Task<CardOperationResult[]> ReadCardID(string cardReaderModuleName)
- {
- var batchOperationTasks = this.cardReaderDeviceHandlers.Select(h =>
- h.ReadCardUID(cardReaderModuleName));
- var results = await Task.WhenAll(batchOperationTasks);
- List<CardOperationResult> final = new List<CardOperationResult>();
- foreach (var r in results)
- final.AddRange(r);
- return final.ToArray();
- }
- [UniversalApi(Description = "Input the plain text key, it'll get encrypted and output a encrypted base64 encoded key which can be safely distributed.")]
- public async Task<string> GenerateLocalEncryptedBase64Key(string plainTextKey)
- {
- return this.keyLoader.EncryptStringToBase64(plainTextKey);
- }
-
-
-
-
-
- [UniversalApi(Description = "Input the plain key set, it'll get encrypted and output a encrypted base64 encoded keyset which can be safely distributed.")]
- public async Task<EncryptedBase64KeySet> GenerateLocalEncryptedBase64KeySet(InputBase64PlainKeySet plainKeySet)
- {
- var output = new EncryptedBase64KeySet();
- output.RootKey = this.keyLoader.EncryptStringToBase64(plainKeySet.RootKey);
- output.文件1读写密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件1读写密钥);
- output.文件1读密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件1读密钥);
- output.文件2读写密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件2读写密钥);
- output.文件2读密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件2读密钥);
- output.文件3读写密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件3读写密钥);
- output.文件3读密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件3读密钥);
- output.文件4读写密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件4读写密钥);
- output.文件4读密钥 = this.keyLoader.EncryptStringToBase64(plainKeySet.文件4读密钥);
- output.Description = plainKeySet.Description;
- return output;
- }
- }
- }
|