2017-10-24 4 views
0

세부 사항에 너무 많이 들어가기 전에 내가 수행하려는 고차원적인 작업은 JavaScript의 일부 데이터를 암호화하여 웹 서버에서 C#으로 암호화 된 데이터를 해독합니다. 문제가있는 부분은 C#에서 데이터를 해독하는 것입니다. 나는이 같은 자바 스크립트에서 일부 데이터를 암호화하고있어RSA-OAEP를 사용하여 JavaScript에서 암호화 된 C#의 데이터 암호 해독시 OAEP 패딩 오류

는 (I는 불필요한 코드를 제거) :

// https://github.com/diafygi/webcrypto-examples#rsa-oaep---encrypt 
window.crypto.subtle.encrypt(
    { 
     name: "RSA-OAEP" 
    }, 
    publicKey, 
    data 
) 
.then(function (encrypted) { 
    // ... 
}); 
내가 그래서 (내가 실제로하지 원하는 점에 유의처럼 자바 스크립트에서 암호를 해독 할 수 있음을 확인

이렇게,하지만 난) 데이터를 해독 할 수 있다는 것을 증명하기 위해 그것을했다 : 간단하게하기 위해, 그 코드 샘플은 "밥"의 이전에 암호화 된 값을 해독한다

function decryptValue() { 

    // Base64 decode the encrypted data for the value "Bob". 
    var data = base64Decode("CthOUMzRdtSwo+4twgtjCA674G3UosWypUZv5E7uxG7GqYPiIJ+E+Uq7vbElp/bahB1fJrgq1qbdMrUZnSypVqBwYnccSxwablO15OOXl9Rn1e7w9V9fuMxtUqvhn+YZezk1623Qd7f5XTYjf6POwixtrgfZtdA+qh00ktKiVBpQKNG/bxhV94fK9+hb+qnzPmXilr9QF5rSQTd4hYHmYcR2ljVCDDZMV3tCVUTecWjS5HbOA1254ve/q3ulBLoPQTE58g7FwDQUZnd7XBdRSwYnrBWTJh8nmJ0PDfn+mCTGEI86S7HtoFYsE+Hezd24Z523phGEVrdMC9Ob1LlXEA=="); 

    // Get private key. 
    var keyPromise = importPrivateKey(); 
    return keyPromise.then(function (privateKey) { 

     // Decrypt the value. 
     return window.crypto.subtle.decrypt(
      { 
       name: "RSA-OAEP" 
      }, 
      privateKey, 
      data 
     ) 
     .then(function (decrypted) { 

      // Log the decrypted value to the console. 
      console.log(arrayBufferToString(decrypted)); 

     }); 

    }); 

} 

. 이것은 잘 작동합니다. 나는 C#에서 값을 해독 할 때

이 문제가 발생합니다

public static string Decrypt() 
{ 

    // The encrypted and base64 encoded value for "Bob". 
    var encryptedValue = "CthOUMzRdtSwo+4twgtjCA674G3UosWypUZv5E7uxG7GqYPiIJ+E+Uq7vbElp/bahB1fJrgq1qbdMrUZnSypVqBwYnccSxwablO15OOXl9Rn1e7w9V9fuMxtUqvhn+YZezk1623Qd7f5XTYjf6POwixtrgfZtdA+qh00ktKiVBpQKNG/bxhV94fK9+hb+qnzPmXilr9QF5rSQTd4hYHmYcR2ljVCDDZMV3tCVUTecWjS5HbOA1254ve/q3ulBLoPQTE58g7FwDQUZnd7XBdRSwYnrBWTJh8nmJ0PDfn+mCTGEI86S7HtoFYsE+Hezd24Z523phGEVrdMC9Ob1LlXEA=="; 

    // Assuming RSA-OAEP. 
    var doOaep = true; 

    // Setup encryption algorithm. 
    var provider = GetPrivateKey(); 

    // Decrypt value. 
    var encryptedData = Convert.FromBase64String(encryptedValue); 
    // This line throws an error: "Error occurred while decoding OAEP padding." 
    var decryptedData = provider.Decrypt(encryptedData, doOaep); 
    var decryptedText = Encoding.Unicode.GetString(decryptedData); 

    // Return decrypted text. 
    return decryptedText; 

} 

provider.Decrypt(encryptedData, doOaep)가의 메시지와 함께 오류가 발생합니다 말한다 라인 "OAEP 패딩을 디코딩하는 동안 오류가 발생했습니다." 스택 추적 :

그것은 자바 스크립트 값을 암호화한다 어쩌면 방법처럼 보인다
Error occurred while decoding OAEP padding. 
    at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey) 
    at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP) 

가 C 번호의 값을 암호화하는 방식과 호환되지 않습니다. 이 접근법을 완전히 포기하고 다른 JavaScript 라이브러리에서 암호화를 시도하기 전에이 오류를 해결할 수있는 방법이 있습니까? https://www.codeproject.com/Articles/11479/RSA-Interoperability-between-JavaScript-and-RSACry

그것은 말합니다 : 자바 스크립트 코드에서

호환되지 않는 패딩 방식은 "나쁜 데이터를 생성 추가로 상황에 대한

,이 오류가이 문서에 언급 된 어떤 관련이 추측하고있다 "예외는 서버 측에서 발생합니다.

자바 스크립트 코드는 따라서 첫 번째의 PKCS # 1 v1.5에 패딩이고 다른 패딩 OAEP (1 V2 PKCS 번호)이고, 두 심 닷넷 RSA 구현에 사용 방식 중 하나를 구현할 필요가있다.

정확한 예외는 표시되지 않지만 어쩌면 해당 문서가 작성된 이후로 오류 메시지가 변경되었을 수 있습니다. 어쨌든이 글에서 말하는 것은 JavaScript가 암호화하는 방식이 C#이 해독하는 방식 (즉, C#의 패딩 요구 사항 때문)과 호환되지 않는다는 것을 암시하는 것처럼 보입니다.

내가 빠진 것이 있나요? 몇 가지 매개 변수 또는 C#에서 작동하는 암호화 및 암호 해독에서 작동하도록하는 간단한 방법이 있습니까? 아마도 JavaScript가 암호화하는 방식과 호환되는 방식으로 해독하는 C# 라이브러리가 있을까요?

다음은 JavaScript가 올바르게 해독되는 일부 예입니다 (일부 브라우저에서만 작동 함).아마) IE에서 작동하지 않을 :

function decryptValue() { 
 

 
    // Base64 decode the encrypted data for the value "Bob". 
 
    var data = base64Decode("CthOUMzRdtSwo+4twgtjCA674G3UosWypUZv5E7uxG7GqYPiIJ+E+Uq7vbElp/bahB1fJrgq1qbdMrUZnSypVqBwYnccSxwablO15OOXl9Rn1e7w9V9fuMxtUqvhn+YZezk1623Qd7f5XTYjf6POwixtrgfZtdA+qh00ktKiVBpQKNG/bxhV94fK9+hb+qnzPmXilr9QF5rSQTd4hYHmYcR2ljVCDDZMV3tCVUTecWjS5HbOA1254ve/q3ulBLoPQTE58g7FwDQUZnd7XBdRSwYnrBWTJh8nmJ0PDfn+mCTGEI86S7HtoFYsE+Hezd24Z523phGEVrdMC9Ob1LlXEA=="); 
 

 
    // Get private key. 
 
    var keyPromise = importPrivateKey(); 
 
    return keyPromise.then(function (privateKey) { 
 

 
     // Decrypt the value. 
 
     return window.crypto.subtle.decrypt(
 
      { 
 
       name: "RSA-OAEP" 
 
      }, 
 
      privateKey, 
 
      data 
 
     ) 
 
     .then(function (decrypted) { 
 

 
      // Log the decrypted value to the console. 
 
      console.log("Decrypted value: " + arrayBufferToString(decrypted)); 
 

 
     }); 
 

 
    }); 
 

 
} 
 

 
function importPrivateKey() { 
 
    var rawKey = { 
 
     "alg": "RSA-OAEP-256", 
 
     "d": "E4KDwgxy7jFrqeXqKjxPTGOdbEoZ2aWj5qcZhUJcnr9Qh_jg_grkgpHVwEbQifTxsipXTiR3_ygspI4XFoeV-wDVfWqWCVR3_bHChF9PW8Ak1x_dBSS28BMs8PdthI1pDbpqPhmMcF4riHCtNo1M1v8cLdeaiqiXitNVBkaTePsDiucfwOy1rgxwBqAL1CNJhP8oRiYkxD-gfE_EapWuXY9-wF9O-lXPLSTKWgMmmVxSmhUP-Uqk7cJ24UH9C7W7hnSQU4pkfD5XHx3_2WO2GMKKZcqz39wJUrQzrIO7539SYsQ3rEe4aMJyL4U-Ib4_purzVS0DRjzGxK8chT2guQ", 
 
     "dp": "kibhWHk1R6yBlhZbjIrNl9beAkyV5vtFsj_F0ixbIITzjSqI_td71sWjKQvJ2rR7hu5DYTZ4p3XwBeQ2jpYQV-y5uh4v7rGngh-0GHuHqMiUQnejgYGcHgng4iCM4e3aTO7QUlP8jqRfxw6xpfNTjrVbAL8LtdCG21vmqOiLkXE", 
 
     "dq": "qLF9x-zKfaXlLsNgBQ1ZnaQexrnJRqrRh9JSU85fCNy5mmpKWAUbCHB-59CGAId8wMAnAyEpjcBOKNTqWSlNzp84xeUHcyPI-Dt4Yp_Y_dXjGAYntALSJs4qeF2rk55MSpiSD_KSU4DknX_E_G2rFMY7AZOSwi1D8YcNmj5okTE", 
 
     "e": "AQAB", 
 
     "ext": true, 
 
     "key_ops": [ 
 
      "decrypt" 
 
     ], 
 
     "kty": "RSA", 
 
     "n": "oQeTwOlTc6rIb2kddwIOc0Ywslc7YzJSRZd_PegW7T3nO3DqCI5kp5EJmnGP8JJ9sbyVYyAHFLZQtMP69UspZFn__fBk2LTp2QdqBSMHbObENcSiG2FH-pZSwCaj3Pvy-qvTjnkxxN-3OE6oB8EcX5ekZwCZzAxazbVXctY_hCcaTWG7ugwc_ZyvhsdE7wa3pnTfXYHWXcDDT8FTpYl62aqWsEIUAJSkgmQ9zce0RiDUjBJyJEM9P0ihp1Ab8BD88pEM22-PXfiOesRzp5yOsjzI3kdr5KPsshstneJEGHYae5GZXLUpnVMRY1TCFFLbkPwK6oVkRaVU1RvK9ssO3Q", 
 
     "p": "2TTEToB4AuPIPPpg3yTyBlGb_m-f4r-TxpU96ConV2p696_4QI6jlPWwgcC9Vdma_Da43AGuyLzIptgkzF8nSjV80VwwDKQ1YkFPc6ZqB2isvExuieSP6_jLlB-fCyCLqtTxpPm2VcK16Pqm0s5T0QGH6cQjjm1r2Ww1wuaiQbk", 
 
     "q": "vcpFwkZKZ3hx3FpHgy3ScuuTRSPO2ge8TE8UMJdCrEnpftAeYuVYrJqnxfzKgyl02OijAUi1eozJxj_lM5McxrKZEEAvo6e8wtzl2hnkUh-KWoBJ8ii0VJcu6U5vs4pcv-lYBPFC6fzoGnUw8LNWMxb5ejgYbLUWp10BbfkWGEU", 
 
     "qi": "Mza7JYleki7BvmD3dX5CO2nkD3mBGz4_0P_aoWyHEkWu4p5XWillaRVWyLnQEubLvAduUCr-lhfNmzdUhHecpE438_LQNtKRyOq9zkvjsMOGDmbkKpZ7-aTSshax6KNlYOWdOkadjuLtRExCmwbzu5lgI4NwacxSs5MfjHMrTCo" 
 
    }; 
 
    return window.crypto.subtle.importKey(
 
     "jwk", 
 
     rawKey, 
 
     { 
 
      name: "RSA-OAEP", 
 
      hash: { name: "SHA-256" } 
 
     }, 
 
     true, 
 
     ["decrypt"] 
 
    ); 
 
} 
 

 
function arrayBufferToString(buffer) { 
 
    var result = ''; 
 
    var bytes = new Uint8Array(buffer); 
 
    for (var i = 0; i < bytes.length; i++) { 
 
     result += String.fromCharCode(bytes[i]); 
 
    } 
 
    return result; 
 
} 
 

 
// Decodes a base64 encoded string into an ArrayBuffer. 
 
// https://stackoverflow.com/a/36378903/2052963 
 
function base64Decode(base64) { 
 
    var binary_string = window.atob(base64); 
 
    return stringToArrayBuffer(binary_string); 
 
} 
 

 
// Converts a string to an ArrayBuffer. 
 
function stringToArrayBuffer(value) { 
 
    var bytes = new Uint8Array(value.length); 
 
    for (var i = 0; i < value.length; i++) { 
 
     bytes[i] = value.charCodeAt(i); 
 
    } 
 
    return bytes.buffer; 
 
} 
 

 
decryptValue();
은 BTW, 내 코드 샘플 중 일부는 내가 사용하고 개인 키를 보여줍니다. 코드를 이해하는 데 도움을주는 것은 의도적 인 일입니다. 사실, 여기에 내가 C#에서 개인 키를 얻고있다 방법은 다음과 같습니다

private static RSACryptoServiceProvider GetPrivateKey() 
{ 
    RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 
    RSAParameters RSAparams = new RSAParameters(); 
    RSAparams.Modulus = Base64UrlDecode("oQeTwOlTc6rIb2kddwIOc0Ywslc7YzJSRZd_PegW7T3nO3DqCI5kp5EJmnGP8JJ9sbyVYyAHFLZQtMP69UspZFn__fBk2LTp2QdqBSMHbObENcSiG2FH-pZSwCaj3Pvy-qvTjnkxxN-3OE6oB8EcX5ekZwCZzAxazbVXctY_hCcaTWG7ugwc_ZyvhsdE7wa3pnTfXYHWXcDDT8FTpYl62aqWsEIUAJSkgmQ9zce0RiDUjBJyJEM9P0ihp1Ab8BD88pEM22-PXfiOesRzp5yOsjzI3kdr5KPsshstneJEGHYae5GZXLUpnVMRY1TCFFLbkPwK6oVkRaVU1RvK9ssO3Q"); 
    RSAparams.Exponent = Base64UrlDecode("AQAB"); 
    RSAparams.D = Base64UrlDecode("E4KDwgxy7jFrqeXqKjxPTGOdbEoZ2aWj5qcZhUJcnr9Qh_jg_grkgpHVwEbQifTxsipXTiR3_ygspI4XFoeV-wDVfWqWCVR3_bHChF9PW8Ak1x_dBSS28BMs8PdthI1pDbpqPhmMcF4riHCtNo1M1v8cLdeaiqiXitNVBkaTePsDiucfwOy1rgxwBqAL1CNJhP8oRiYkxD-gfE_EapWuXY9-wF9O-lXPLSTKWgMmmVxSmhUP-Uqk7cJ24UH9C7W7hnSQU4pkfD5XHx3_2WO2GMKKZcqz39wJUrQzrIO7539SYsQ3rEe4aMJyL4U-Ib4_purzVS0DRjzGxK8chT2guQ"); 
    RSAparams.P = Base64UrlDecode("2TTEToB4AuPIPPpg3yTyBlGb_m-f4r-TxpU96ConV2p696_4QI6jlPWwgcC9Vdma_Da43AGuyLzIptgkzF8nSjV80VwwDKQ1YkFPc6ZqB2isvExuieSP6_jLlB-fCyCLqtTxpPm2VcK16Pqm0s5T0QGH6cQjjm1r2Ww1wuaiQbk"); 
    RSAparams.Q = Base64UrlDecode("vcpFwkZKZ3hx3FpHgy3ScuuTRSPO2ge8TE8UMJdCrEnpftAeYuVYrJqnxfzKgyl02OijAUi1eozJxj_lM5McxrKZEEAvo6e8wtzl2hnkUh-KWoBJ8ii0VJcu6U5vs4pcv-lYBPFC6fzoGnUw8LNWMxb5ejgYbLUWp10BbfkWGEU"); 
    RSAparams.DP = Base64UrlDecode("kibhWHk1R6yBlhZbjIrNl9beAkyV5vtFsj_F0ixbIITzjSqI_td71sWjKQvJ2rR7hu5DYTZ4p3XwBeQ2jpYQV-y5uh4v7rGngh-0GHuHqMiUQnejgYGcHgng4iCM4e3aTO7QUlP8jqRfxw6xpfNTjrVbAL8LtdCG21vmqOiLkXE"); 
    RSAparams.DQ = Base64UrlDecode("qLF9x-zKfaXlLsNgBQ1ZnaQexrnJRqrRh9JSU85fCNy5mmpKWAUbCHB-59CGAId8wMAnAyEpjcBOKNTqWSlNzp84xeUHcyPI-Dt4Yp_Y_dXjGAYntALSJs4qeF2rk55MSpiSD_KSU4DknX_E_G2rFMY7AZOSwi1D8YcNmj5okTE"); 
    RSAparams.InverseQ = Base64UrlDecode("Mza7JYleki7BvmD3dX5CO2nkD3mBGz4_0P_aoWyHEkWu4p5XWillaRVWyLnQEubLvAduUCr-lhfNmzdUhHecpE438_LQNtKRyOq9zkvjsMOGDmbkKpZ7-aTSshax6KNlYOWdOkadjuLtRExCmwbzu5lgI4NwacxSs5MfjHMrTCo"); 
    RSA.ImportParameters(RSAparams); 
    return RSA; 
} 

// From the PDF here: https://www.rfc-editor.org/info/rfc7515 
// Also see: https://auth0.com/docs/jwks 
public static byte[] Base64UrlDecode(string arg) 
{ 
    string s = arg; 
    s = s.Replace('-', '+'); // 62nd char of encoding 
    s = s.Replace('_', '/'); // 63rd char of encoding 
    switch (s.Length % 4) // Pad with trailing '='s 
    { 
     case 0: break; // No pad chars in this case 
     case 2: s += "=="; break; // Two pad chars 
     case 3: s += "="; break; // One pad char 
     default: 
      throw new System.Exception(
     "Illegal base64url string!"); 
    } 
    return Convert.FromBase64String(s); // Standard base64 decoder 
} 
+0

나는 당신이 C#으로해야하는 것은 자바의 RSA/ECB/OAEPWithSHA-256AndMGF1Padding과 동일한 경우는 잘 모르겠지만, 만약 그렇다면, 당신이 시도하는 것이 좋습니다 https://github.com/digitalbazaar/forge #rsa. 이 경우 WebCrypto 대신 JavaScript에서 Forge를 사용할 수 있습니다. – Darlesson

+2

자바 스크립트는 SHA-256을 해시 함수 및 MGF1 함수로 사용하여 RSA OAEP로 암호화됩니다. .NET은 단순히이를 지원하지 않습니다. 오라클 자바는 Bouncycastle 자바와 C# 라이브러리를 사용합니다. –

+0

@JamesKPolk 정보를 제공해 주셔서 감사합니다. 그것이 "MGF1"이라는 용어를 처음 들었습니다. Bouncy Castle for C#을 사용하면 암호 해독이 작동한다고 생각합니까? –

답변

1

당신이 RSACng에 RSACryptoServiceProvider에서 이동해야 SHA-2-256와 OAEP을 사용하기 때문에 (.NET 4.6+). ctor 호출과는 별도로 어떤 구현이 사용되고 있는지에 대한 지식을 제거했습니다. 내가 Windows 컴퓨터에 대한 액세스 권한이없는 모노 분명히 RSACng를 구현하지 않기 때문에

private static RSA GetPrivateKey() 
{ 
    // build the RSAParams as before, then 
    RSA rsa = new RSACng(); 
    rsa.ImportParameters(RSAparams); 
    return rsa; 
} 

// Setup encryption algorithm. 
var provider = GetPrivateKey(); 
... 
var decryptedData = provider.Decrypt(encryptedData, RSAEncryptionPadding.OaepSHA256); 
+0

또한 MGF 기능에 SHA-256을 사용합니까? 분명히 Mono는 RSACng을 구현하지 않으므로 메시지를 해독하는지 여부를 테스트 할 수는 없습니다. –

+0

@JamesKPolk 예, 그 옵션은 SHA-2-256이있는 MGF-1이고 빈 레이블입니다. – bartonjs

+0

나는이 질문을 내가 가진 주요 질문에 대한 가장 직접적인 대답이기 때문에 대답으로 표시했다. @ JamesKPolk이 지적했듯이, 원래의 질문에 더 부수적이지만 인코딩을 변경해야했습니다. 고마워! –

1

나는 @bartonjs's 대답을 테스트 할 수 없습니다입니다. 아래는 Bouncycastle C# 라이브러리를 사용하여 암호문을 해독하는 예제입니다. OaepPadding(...)는 Oaep 해시와 MGF 해시 모두에 대해 SHA-256을 사용합니다. 이것은 분명히 귀하의 자바 스크립트 코드와 상호 운용하는 데 필요한 무엇입니까. 또한 Encoding.Unicode.GetString()을 사용하는 반면 Encoding.UTF8.GetString()을 사용했음을 유의하십시오. 인코딩은 확실히 UTF-16이 아니며 Encoding.Unicode이 제공합니다.

using System; 
using System.Text; 
using Org.BouncyCastle.Crypto; 
using Org.BouncyCastle.Crypto.Digests; 
using Org.BouncyCastle.Crypto.Encodings; 
using Org.BouncyCastle.Crypto.Engines; 
using Org.BouncyCastle.Crypto.Parameters; 
using Org.BouncyCastle.Math; 

namespace RsaSha256OaepDecrypt 
{ 
    class MainClass 
    { 
     public static void Main(string[] args) 
     { 
      var encryptedValue = "CthOUMzRdtSwo+4twgtjCA674G3UosWypUZv5E7uxG7GqYPiIJ+E+Uq7vbElp/bahB1fJrgq1qbdMrUZnSypVqBwYnccSxwablO15OOXl9Rn1e7w9V9fuMxtUqvhn+YZezk1623Qd7f5XTYjf6POwixtrgfZtdA+qh00ktKiVBpQKNG/bxhV94fK9+hb+qnzPmXilr9QF5rSQTd4hYHmYcR2ljVCDDZMV3tCVUTecWjS5HbOA1254ve/q3ulBLoPQTE58g7FwDQUZnd7XBdRSwYnrBWTJh8nmJ0PDfn+mCTGEI86S7HtoFYsE+Hezd24Z523phGEVrdMC9Ob1LlXEA=="; 
      var encryptedData = Convert.FromBase64String(encryptedValue); 
      var rsaPrivate = GetPrivateKey(); 
      IAsymmetricBlockCipher cipher0 = new RsaBlindedEngine(); 
      cipher0 = new OaepEncoding(cipher0, new Sha256Digest(), new Sha256Digest(), null); 
      BufferedAsymmetricBlockCipher cipher = new BufferedAsymmetricBlockCipher(cipher0); 
      cipher.Init(false, rsaPrivate); 
      cipher.ProcessBytes(encryptedData, 0, encryptedData.Length); 
      var decryptedData = cipher.DoFinal(); 
      var decryptedText = Encoding.UTF8.GetString(decryptedData); 
      Console.WriteLine(decryptedText); 
     } 

     private static BigInteger makeBigInt(String b64Url) 
     { 
      var bytes = Base64UrlDecode(b64Url); 
      if ((sbyte)bytes[0] < 0) 
      { 
       // prepend a zero byte to make it positive. 
       var bytes1 = new byte[bytes.Length + 1]; 
       bytes1[0] = 0; 
       bytes.CopyTo(bytes1, 1); 
       bytes = bytes1; 
      } 

      return new BigInteger(bytes); 
     } 
     private static AsymmetricKeyParameter GetPrivateKey() 
     { 
      //RSAParameters RSAparams = new RSAParameters(); 
      var Modulus = makeBigInt("oQeTwOlTc6rIb2kddwIOc0Ywslc7YzJSRZd_PegW7T3nO3DqCI5kp5EJmnGP8JJ9sbyVYyAHFLZQtMP69UspZFn__fBk2LTp2QdqBSMHbObENcSiG2FH-pZSwCaj3Pvy-qvTjnkxxN-3OE6oB8EcX5ekZwCZzAxazbVXctY_hCcaTWG7ugwc_ZyvhsdE7wa3pnTfXYHWXcDDT8FTpYl62aqWsEIUAJSkgmQ9zce0RiDUjBJyJEM9P0ihp1Ab8BD88pEM22-PXfiOesRzp5yOsjzI3kdr5KPsshstneJEGHYae5GZXLUpnVMRY1TCFFLbkPwK6oVkRaVU1RvK9ssO3Q"); 
      var Exponent = makeBigInt("AQAB"); 
      var D = makeBigInt("E4KDwgxy7jFrqeXqKjxPTGOdbEoZ2aWj5qcZhUJcnr9Qh_jg_grkgpHVwEbQifTxsipXTiR3_ygspI4XFoeV-wDVfWqWCVR3_bHChF9PW8Ak1x_dBSS28BMs8PdthI1pDbpqPhmMcF4riHCtNo1M1v8cLdeaiqiXitNVBkaTePsDiucfwOy1rgxwBqAL1CNJhP8oRiYkxD-gfE_EapWuXY9-wF9O-lXPLSTKWgMmmVxSmhUP-Uqk7cJ24UH9C7W7hnSQU4pkfD5XHx3_2WO2GMKKZcqz39wJUrQzrIO7539SYsQ3rEe4aMJyL4U-Ib4_purzVS0DRjzGxK8chT2guQ"); 
      var P = makeBigInt("2TTEToB4AuPIPPpg3yTyBlGb_m-f4r-TxpU96ConV2p696_4QI6jlPWwgcC9Vdma_Da43AGuyLzIptgkzF8nSjV80VwwDKQ1YkFPc6ZqB2isvExuieSP6_jLlB-fCyCLqtTxpPm2VcK16Pqm0s5T0QGH6cQjjm1r2Ww1wuaiQbk"); 
      var Q = makeBigInt("vcpFwkZKZ3hx3FpHgy3ScuuTRSPO2ge8TE8UMJdCrEnpftAeYuVYrJqnxfzKgyl02OijAUi1eozJxj_lM5McxrKZEEAvo6e8wtzl2hnkUh-KWoBJ8ii0VJcu6U5vs4pcv-lYBPFC6fzoGnUw8LNWMxb5ejgYbLUWp10BbfkWGEU"); 
      var DP = makeBigInt("kibhWHk1R6yBlhZbjIrNl9beAkyV5vtFsj_F0ixbIITzjSqI_td71sWjKQvJ2rR7hu5DYTZ4p3XwBeQ2jpYQV-y5uh4v7rGngh-0GHuHqMiUQnejgYGcHgng4iCM4e3aTO7QUlP8jqRfxw6xpfNTjrVbAL8LtdCG21vmqOiLkXE"); 
      var DQ = makeBigInt("qLF9x-zKfaXlLsNgBQ1ZnaQexrnJRqrRh9JSU85fCNy5mmpKWAUbCHB-59CGAId8wMAnAyEpjcBOKNTqWSlNzp84xeUHcyPI-Dt4Yp_Y_dXjGAYntALSJs4qeF2rk55MSpiSD_KSU4DknX_E_G2rFMY7AZOSwi1D8YcNmj5okTE"); 
      var InverseQ = makeBigInt("Mza7JYleki7BvmD3dX5CO2nkD3mBGz4_0P_aoWyHEkWu4p5XWillaRVWyLnQEubLvAduUCr-lhfNmzdUhHecpE438_LQNtKRyOq9zkvjsMOGDmbkKpZ7-aTSshax6KNlYOWdOkadjuLtRExCmwbzu5lgI4NwacxSs5MfjHMrTCo"); 
      var rsa = new RsaPrivateCrtKeyParameters(Modulus, Exponent, D, P, Q, DP, DQ, InverseQ); 
      return rsa; 
     } 

     // From the PDF here: https://www.rfc-editor.org/info/rfc7515 
     // Also see: https://auth0.com/docs/jwks 

     public static byte[] Base64UrlDecode(string arg) 
     { 
      string s = arg; 
      s = s.Replace('-', '+'); // 62nd char of encoding 
      s = s.Replace('_', '/'); // 63rd char of encoding 
      switch (s.Length % 4) // Pad with trailing '='s 
      { 
       case 0: break; // No pad chars in this case 
       case 2: s += "=="; break; // Two pad chars 
       case 3: s += "="; break; // One pad char 
       default: 
        throw new System.Exception(
       "Illegal base64url string!"); 
      } 
      return Convert.FromBase64String(s); // Standard base64 decoder 
     } 
    } 
} 
+0

나는 이것을 아직 시도 할 기회가 없었지만 다음 주에 그렇게 할 것입니다. 게시 된 답변으로 인해 .NET 4.6으로 업그레이드 할 수 있는지 확실하지 않으므로 실제로 제안 된 솔루션을 사용하게 될 수도 있습니다. 또한 인코딩 관련 메모에 감사드립니다. 고마워. 당신 정말 대단하네요! –