首页 > 编程语言 >C# PKCS8

C# PKCS8

时间:2023-12-26 09:56:10浏览次数:45  
标签:return C# Length int PKCS8 bs new byte

背景

C#项目要携带用户信息,通过JWT, 跳转到Java项目。为了验证Token,所以用于签名的key和算法必须一致。

Java项目JWT的实现

String secret = "PKCS8 encode private key";
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(secret));
KeyFactory kf = KeyFactory.getInstance(Constants.ENCRYPTION_TYPE_RSA);
PrivateKey privateKey = kf.generatePrivate(keySpec);

Jwts.builder().setClaims(claims).setExpiration(expirationDate).signWith(privateKey, SignatureAlgorithm.RS256).compact();

C#对应实现

Source: https://github.com/googleapis/google-api-dotnet-client/blob/main/Src/Support/Google.Apis.Auth/OAuth2/Pkcs8.cs

/*
Copyright 2016 Google Inc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using Google.Apis.Util;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;

namespace Google.Apis.Auth.OAuth2
{
    internal class Pkcs8
    {
        // PKCS#8 specification: https://www.ietf.org/rfc/rfc5208.txt
        // ASN.1 specification: https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf

        /// <summary>
        /// An incomplete ASN.1 decoder, only implements what's required
        /// to decode a Service Credential.
        /// </summary>
        internal class Asn1
        {
            internal enum Tag
            {
                Integer = 2,
                OctetString = 4,
                Null = 5,
                ObjectIdentifier = 6,
                Sequence = 16,
            }

            internal class Decoder
            {
                public Decoder(byte[] bytes)
                {
                    _bytes = bytes;
                    _index = 0;
                }

                private byte[] _bytes;
                private int _index;

                public object Decode()
                {
                    Tag tag = ReadTag();
                    switch (tag)
                    {
                        case Tag.Integer:
                            return ReadInteger();
                        case Tag.OctetString:
                            return ReadOctetString();
                        case Tag.Null:
                            return ReadNull();
                        case Tag.ObjectIdentifier:
                            return ReadOid();
                        case Tag.Sequence:
                            return ReadSequence();
                        default:
                            throw new NotSupportedException($"Tag '{tag}' not supported.");
                    }
                }

                private byte NextByte() => _bytes[_index++];

                private byte[] ReadLengthPrefixedBytes()
                {
                    int length = ReadLength();
                    return ReadBytes(length);
                }

                private byte[] ReadInteger() => ReadLengthPrefixedBytes();

                private object ReadOctetString()
                {
                    byte[] bytes = ReadLengthPrefixedBytes();
                    return new Decoder(bytes).Decode();
                }

                private object ReadNull()
                {
                    int length = ReadLength();
                    if (length != 0)
                    {
                        throw new InvalidDataException("Invalid data, Null length must be 0.");
                    }
                    return null;
                }

                private int[] ReadOid()
                {
                    byte[] oidBytes = ReadLengthPrefixedBytes();
                    List<int> result = new List<int>();
                    bool first = true;
                    int index = 0;
                    while (index < oidBytes.Length)
                    {
                        int subId = 0;
                        byte b;
                        do
                        {
                            b = oidBytes[index++];
                            if ((subId & 0xff000000) != 0)
                            {
                                throw new NotSupportedException("Oid subId > 2^31 not supported.");
                            }
                            subId = (subId << 7) | (b & 0x7f);
                        } while ((b & 0x80) != 0);
                        if (first)
                        {
                            first = false;
                            result.Add(subId / 40);
                            result.Add(subId % 40);
                        }
                        else
                        {
                            result.Add(subId);
                        }
                    }
                    return result.ToArray();
                }

                private object[] ReadSequence()
                {
                    int length = ReadLength();
                    int endOffset = _index + length;
                    if (endOffset < 0 || endOffset > _bytes.Length)
                    {
                        throw new InvalidDataException("Invalid sequence, too long.");
                    }
                    List<object> sequence = new List<object>();
                    while (_index < endOffset)
                    {
                        sequence.Add(Decode());
                    }
                    return sequence.ToArray();
                }

                private byte[] ReadBytes(int length)
                {
                    if (length <= 0)
                    {
                        throw new ArgumentOutOfRangeException(nameof(length), "length must be positive.");
                    }
                    if (_bytes.Length - length < 0)
                    {
                        throw new ArgumentException("Cannot read past end of buffer.");
                    }
                    byte[] result = new byte[length];
                    Array.Copy(_bytes, _index, result, 0, length);
                    _index += length;
                    return result;
                }

                private Tag ReadTag()
                {
                    byte b = NextByte();
                    int tag = b & 0x1f;
                    if (tag == 0x1f)
                    {
                        // A tag value of 0x1f (31) indicates a tag value of >30 (spec section 8.1.2.4)
                        throw new NotSupportedException("Tags of value > 30 not supported.");
                    }
                    else
                    {
                        return (Tag)tag;
                    }
                }

                private int ReadLength()
                {
                    byte b0 = NextByte();
                    if ((b0 & 0x80) == 0)
                    {
                        return b0;
                    }
                    else
                    {
                        if (b0 == 0xff)
                        {
                            throw new InvalidDataException("Invalid length byte: 0xff");
                        }
                        int byteCount = b0 & 0x7f;
                        if (byteCount == 0)
                        {
                            throw new NotSupportedException("Lengths in Indefinite Form not supported.");
                        }
                        int result = 0;
                        for (int i = 0; i < byteCount; i++)
                        {
                            if ((result & 0xff800000) != 0)
                            {
                                throw new NotSupportedException("Lengths > 2^31 not supported.");
                            }
                            result = (result << 8) | NextByte();
                        }
                        return result;
                    }
                }

            }

            public static object Decode(byte[] bs) => new Decoder(bs).Decode();

        }

        public static RSAParameters DecodeRsaParameters(string pkcs8PrivateKey)
        {
            const string PrivateKeyPrefix = "-----BEGIN PRIVATE KEY-----";
            const string PrivateKeySuffix = "-----END PRIVATE KEY-----";

            Utilities.ThrowIfNullOrEmpty(pkcs8PrivateKey, nameof(pkcs8PrivateKey));
            pkcs8PrivateKey = pkcs8PrivateKey.Trim();
            if (!pkcs8PrivateKey.StartsWith(PrivateKeyPrefix, StringComparison.Ordinal) ||
                !pkcs8PrivateKey.EndsWith(PrivateKeySuffix, StringComparison.Ordinal))
            {
                throw new ArgumentException(
                    $"PKCS8 data must be contained within '{PrivateKeyPrefix}' and '{PrivateKeySuffix}'.", nameof(pkcs8PrivateKey));
            }
            string base64PrivateKey =
                pkcs8PrivateKey.Substring(PrivateKeyPrefix.Length, pkcs8PrivateKey.Length - PrivateKeyPrefix.Length - PrivateKeySuffix.Length);
            // FromBase64String() ignores whitespace, so further Trim()ing isn't required.
            byte[] pkcs8Bytes = Convert.FromBase64String(base64PrivateKey);

            object ans1 = Asn1.Decode(pkcs8Bytes);
            object[] parameters = (object[])((object[])ans1)[2];

            var rsaParmeters = new RSAParameters
            {
                Modulus = TrimLeadingZeroes((byte[])parameters[1]),
                Exponent = TrimLeadingZeroes((byte[])parameters[2], alignTo8Bytes: false),
                D = TrimLeadingZeroes((byte[])parameters[3]),
                P = TrimLeadingZeroes((byte[])parameters[4]),
                Q = TrimLeadingZeroes((byte[])parameters[5]),
                DP = TrimLeadingZeroes((byte[])parameters[6]),
                DQ = TrimLeadingZeroes((byte[])parameters[7]),
                InverseQ = TrimLeadingZeroes((byte[])parameters[8]),
            };

            return rsaParmeters;
        }

        internal static byte[] TrimLeadingZeroes(byte[] bs, bool alignTo8Bytes = true)
        {
            int zeroCount = 0;
            while (zeroCount < bs.Length && bs[zeroCount] == 0) zeroCount += 1;

            int newLength = bs.Length - zeroCount;
            if (alignTo8Bytes)
            {
                int remainder = newLength & 0x07;
                if (remainder != 0)
                {
                    newLength += 8 - remainder;
                }
            }

            if (newLength == bs.Length)
            {
                return bs;
            }

            byte[] result = new byte[newLength];
            if (newLength < bs.Length)
            {
                Buffer.BlockCopy(bs, bs.Length - newLength, result, 0, newLength);
            }
            else
            {
                Buffer.BlockCopy(bs, 0, result, newLength - bs.Length, bs.Length);
            }
            return result;
        }

    }
}

标签:return,C#,Length,int,PKCS8,bs,new,byte
From: https://www.cnblogs.com/talentzemin/p/17927452.html

相关文章

  • LocPatcH An efficient long-read hybrid error correction algorithm based on local
    该文档主要介绍了一种基于装配的方法和概率隐藏马尔科夫模型(pHMM)用于纠正长读序列的错误。文档详细描述了对酵母数据进行实验的结果、纠正方法的拓扑结构以及实验设置和数据集。 这种基于装配的纠正方法相对于直接纠正存在哪些优势?pHMM的拓扑结构是怎样的?......
  • linux声音处理 alsa & jack 是什么
    alsa(AdvancedLinuxSoundArchitecture)是什么:简单的说,linux之前的内核里处理声音使用oss,后来大家觉得不好用,重写了声音部分,改名叫alsa(更高级的),并且提供了用户空间库(alsa-lib),供应用程序方便调用。官方说明:高级Linux声音架构(ALSA)为Linux操作系统提供音频和MIDI......
  • C# 中使用 using 关键字和不使用 using 关键字创建 FileStream
    在C#中使用using关键字和不使用using关键字创建FileStream实例之间有一些区别。使用using关键字:using(FileStreamfileStream=newFileStream(filePath,FileMode.Open,FileAccess.Read)){//使用fileStream进行操作}using关键字用于创建FileStream......
  • 深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs
    通过这篇文章你可以了解到Docker容器的核心实现原理,包括Namespace、Cgroups、Rootfs等三个核心功能。如果你对云原生技术充满好奇,想要深入了解更多相关的文章和资讯,欢迎关注微信公众号。搜索公众号【探索云原生】即可订阅后续文章会演示如何从零实现一个简易的Docker,......
  • CSS中的各种居中
    在CSS布局时经常会需要实现水平居中,垂直居中,水平垂直居中这样的要求但是却又不是非常的在意,所以总结一下。文本水平居中1.使用text-align属性:将容器的text-align属性设置为"center",可以使文本在容器中水平居中。<style>.container{width:500px;......
  • long-read error correction algorithms”
    “long-readerrorcorrectionalgorithms”是指用于纠正长读长测序数据中错误的算法。长读长测序技术能够产生更长的DNA或RNA序列,但也容易受到测序过程中的错误影响。这些算法通过分析测序数据中的错误模式和参考序列信息,识别和纠正错误,从而提高长读长测序数据的准确性和可靠性。......
  • Unity3D MVC框架和MVVM框架优缺点详解
    Unity3D是一款非常流行的游戏开发引擎,它为开发者提供了强大的工具和功能,使得开发者能够轻松地创建各种类型的游戏。在Unity3D中,使用模型-视图-控制器(MVC)框架和模型-视图-视图模型(MVVM)框架可以更好地组织和管理游戏的逻辑和界面。对啦!这里有个游戏开发交流小组里面聚集了一帮热爱......
  • .Net 利用Aspose.Words在上传word时将.doc转为.docx
    1、引用包Aspose.Words2、接口中使用:ListformFiles=new();foreach(IFormFileformFileinformCollection.Files){if(formFile.ContentType=="application/msword"){Streamfs=formFile.OpenReadStream();vardoc=newAspose.Words.Document(fs);Stream......
  • 【开源项目推荐】Apache Superset——最优秀的开源数据可视化与数据探索平台
    大家好,我是独孤风。数据可视化是数据领域一个非常重要的应用。而结合了数据可视化和数据探索功能的BI(商业智能)工具,更是被各大公司青睐。但是,由于数据可视化工具的开发成本过高,长期以来一直是商业化的BI工具处于垄断地位。那么,有没有优秀的开源数据可视化与数据探索平台呢?今天......
  • docker-compose 快速运行java程序
    1、任意目录新建docker-compose.ymltouchdocker-compose.ymlmdkirconfigtouchconfig/application.yml2、复制jar文件到docker-compose.yml所在目录cp3、修改docker-compose.ymlversion:'3'services:qyweixin_server:image:image:harbor.iotwedora.com:4018......