성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
[공진영] 안녕하세요 좋은글 감사합니다. 현재 제가 wpf로 관제 모...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>RSAParameters 와 System.Numerics.BigInteger 이야기</h1> <p> <br /> RSAParameters는 다음과 같이 간단한 구조체에 불과합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [Serializable, StructLayout(LayoutKind.Sequential), ComVisible(true)] public struct RSAParameters { public byte[] Exponent; <span style='color: blue; font-weight: bold'>public byte[] Modulus;</span> [NonSerialized] <span style='color: blue; font-weight: bold'>public byte[] P;</span> [NonSerialized] <span style='color: blue; font-weight: bold'>public byte[] Q;</span> [NonSerialized] public byte[] DP; [NonSerialized] public byte[] DQ; [NonSerialized] public byte[] InverseQ; [NonSerialized] public byte[] D; } </pre> <br /> RSA에 대해서 아시거나... 혹은 다음의 도움말을 참고해보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > RSAParameters Structure ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsaparameters'>https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.rsaparameters</a> </pre> <br /> 아래의 공식이 성립하는 것을 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Modulus == D * Q </pre> <br /> 그럼, 정말로 그런지 한번 테스트 해볼까요? 이를 확인하기 위해 System.Security.Cryptography.RSAParameters 타입을 생성하면 되는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); Console.WriteLine(rsa.KeySize); // 1024 System.Security.Cryptography.RSAParameters rsaParam = rsa.ExportParameters(true); </pre> <br /> 여기서 "KeySize == Modulus 비트 수"입니다. RSACryptoServiceProvider 타입은 (Microsoft Enhanced Cryptographic Provider에 의해) 기본적으로 1024 길이의 비트를 생성하기 때문에, 따라서 Modulus 값은 (1024 / 8) == 128바이트의 배열이 되고, 소수인 D 와 Q 값은 64바이트로 구성됩니다. 그렇다면, 64바이트 값을 어떻게 숫자로 표현할 수 있을까요? int == 4바이트, long == 8바이트이기 때문에 이런 경우는 .NET 4.0에서 새롭게 제공되는 System.Numerics.BigInteger 타입을 이용해야 합니다.<br /> <br /> 그렇게 해서 최종적으로 검증해 보면 다음과 같이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > var rsaParam = rsa.ExportParameters(true); <span style='color: blue; font-weight: bold'>BigInteger p = new BigInteger(rsaParam.P); BigInteger q = new BigInteger(rsaParam.Q); </span> Console.WriteLine("P == " + p); Console.WriteLine(); Console.WriteLine("Q == " + q); Console.WriteLine(); Console.WriteLine(); <span style='color: blue; font-weight: bold'>BigInteger expectModulus = p * q;</span> <span style='color: blue; font-weight: bold'>BigInteger realModulus = new BigInteger(rsaParam.Modulus);</span> Console.WriteLine("expect == " + expectModulus); Console.WriteLine(); Console.WriteLine("real == " + realModulus); Console.WriteLine(); Console.WriteLine(); Console.WriteLine(expectModulus == realModulus); // 출력 결과 P == 1745347117586124307562205124286981362442227763277912640750731532696045914361892339770449856387948878818154992652330479951788437061857370883395881528451063 Q == -2831377943566696349004974146379573665554872347974010564465244410976940341475835118677977005548443979634625788268996007446130714733671878050920424168711433 <span style='color: blue; font-weight: bold'>expect == -4941737332601061606570187639549427718961295189156172733040629026496217387840960517507341781860167036894747005869475064044704332300007926725569534038965955079267069563372191094586565054803509844616827366332886219041144233218481874255267563142125606547422977188664512747390151137223352939005270173921109103279 real == -16006374138550337361913895556834746249117422527852669572216124554020516563250980797049053677292949829318290649342785628587299165879371350772513931531074679499167095600766366968566255398032852895784920219487284111177709190850812490257181200566885064876772887181829227853031677929745974169705512945745218126097 </span> False </pre> <br /> 솔직히, 위의 결과를 보고 매우 당혹스러웠는데요. codeproject에서 다음의 클래스를 다운로드해서 다시 검증을 시도해 보면서 희미하게 나마 길이 보이기 시작했습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# BigInteger Class ; <a target='tab' href='http://www.codeproject.com/Articles/2728/C-BigInteger-Class'>http://www.codeproject.com/Articles/2728/C-BigInteger-Class</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > P == 13166127462085329373727425166872120986194216491356932086431169554619716019875387246531996148969249129949565580040266682598776454158918312549723959628032699 Q == 11390141563278975215819305956455532350216609406733079257245450072905569011882636528766209599715416605839390753590072712761658668466252783809241838580216743 expect == 149964055633326840002477251389683051260311657686489276520978618664425141749178160915585112396507001611162179675210170283871705549806201579779103084984128959100324337444518674590820398847138520023398114796723776140324034040066128137956589979334949391106309587487953021118120395908293916435156067301386111279357 real == 149964055633326840002477251389683051260311657686489276520978618664425141749178160915585112396507001611162179675210170283871705549806201579779103084984128959100324337444518674590820398847138520023398114796723776140324034040066128137956589979334949391106309587487953021118120395908293916435156067301386111279357 True </pre> <br /> 세상에... .NET 4.0 클래스에서는 예기치 않은 결과가 나온 반면, codeproject에서 다운로드한 BigInteger는 정상적으로 검증이 된 것입니다.<br /> <br /> 도대체, System.Numerics.BigInteger에 어떤 차이점이 있는 걸까요?<br /> <br /> <hr style='width: 50%' /><br /> <br /> 차이를 확인하기 위해 다음과 같이 간단한 배열을 사용해서 초기화를 해봤습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { <span style='color: blue; font-weight: bold'>byte[] t1 = new byte[] { 0xF0, 0, 0, 0, 0, 0, 0, 0, 0 }; // 0xF0 == 240</span> BigInteger b1 = new BigInteger(t1); Console.WriteLine("codeproject BigInteger == " + b1); System.Numerics.BigInteger nb1 = new System.Numerics.BigInteger(t1); Console.WriteLine(".NET 4.0 BigInteger == " + nb1); } // 출력 결과 codeproject BigInteger == <span style='color: blue; font-weight: bold'>4427218577690292387840</span> .NET 4.0 BigInteger == <span style='color: blue; font-weight: bold'>240</span> </pre> <br /> 짐작하시겠지요? 이것을 기반으로 도움말을 찾아보니,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > BigInteger Constructor (Byte[]) ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.-ctor'>https://learn.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.-ctor</a> </pre> <br /> Little endian 이야기가 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > The individual bytes in the value array should be in little-endian order </pre> <br /> 아하... 그렇다면, RSAParameters의 인자에 기록되어 있던 모든 바이트 배열은 Big Endian 식으로 기록한 값이라는 의미가 되는군요.<br /> <br /> 따라서, System.Numerics.BigInteger에서 RSAParameters의 개별값들을 정상적으로 인식시키기 위해서는 역순 배열을 해주어야 합니다.<br /> <br /> 그런데, 차이점은 그뿐만이 아닙니다. 위의 예제 코드를 다음과 같이 바꿔보면 알 수 있는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { byte[] t1 = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0xF0 }; // 0xF0 == 240 BigInteger b1 = new BigInteger(t1); Console.WriteLine("codeproject BigInteger == " + b1); System.Numerics.BigInteger nb1 = new System.Numerics.BigInteger(t1); Console.WriteLine(".NET 4.0 BigInteger == " + nb1); byte[] nb1Bytes = nb1.ToByteArray(); } codeproject BigInteger == 240 .NET 4.0 BigInteger == -295147905179352825856 </pre> <br /> 원했던 결과는 4427218577690292387840인데, 엉뚱하게 -295147905179352825856라는 음수값이 나온 것입니다. System.Numerics.BigInteger와 codeproject의 BigInteger 간의 두 번째 차이점이 바로 '음수 표현'입니다.<br /> <br /> System.Numerics.BigInteger는, 2의 보수표현에 의한 signed 지원을 하고 있는 반면 codeproject의 BigInteger 값은 -1을 표현하려면 280개의 255 값을 가진 바이트 배열이 필요합니다. (정확히 그 수가 아니면 unsigned BigInteger로 표현을 합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 자... 그럼, 대강 준비가 모두 끝났습니다.<br /> <br /> 위의 내용에 기반해서 RSAParameters의 값들을 설명해 보면, 모두 unsigned에다가 BigEndian으로 표현되어 있다는 점입니다.<br /> <br /> 따라서, 최종적으로 아래와 같이 코드를 만들어 주면, Modulus == P * Q 식을 검증할 수 있게 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > { List<byte> pList = new List<byte>(); <span style='color: blue; font-weight: bold'>pList.Add(0); pList.AddRange(rsaParam.P); pList.Reverse();</span> List<byte> qList = new List<byte>(); <span style='color: blue; font-weight: bold'>qList.Add(0); qList.AddRange(rsaParam.Q); qList.Reverse();</span> System.Numerics.BigInteger p = new System.Numerics.BigInteger(pList.ToArray()); System.Numerics.BigInteger q = new System.Numerics.BigInteger(qList.ToArray()); Console.WriteLine("P == " + p); Console.WriteLine(); Console.WriteLine("Q == " + q); Console.WriteLine(); Console.WriteLine(); System.Numerics.BigInteger expectModulus = p * q; List<byte> modList = new List<byte>(); <span style='color: blue; font-weight: bold'>modList.Add(0); modList.AddRange(rsaParam.Modulus); modList.Reverse();</span> System.Numerics.BigInteger realModulus = new System.Numerics.BigInteger(modList.ToArray()); Console.WriteLine("expect == " + expectModulus); Console.WriteLine(); Console.WriteLine("real == " + realModulus); Console.WriteLine(); Console.WriteLine(); Console.WriteLine(expectModulus == realModulus); } // 출력 결과 P == 13122761769973223728438748421120966940822111822658737846751726458201009787842568183226633956353767366852373536207830897524429703477826413101329242841991559 Q == 12143591235989542801897500592593786940177231874673557922727626132792109878234051570051285301506807193717599879021393783668476782936432195855587786810886413 expect == 159357454821825460303855513529351666165351910023005057152558643457380993169002523181064440400043956860957806683852053087023978010188144107163145164586420445263064724930686003901511627395052659481408547123871407008485127664685784237943462320106826498735373812869875643428632125173297462470986055646835053787867 real == 159357454821825460303855513529351666165351910023005057152558643457380993169002523181064440400043956860957806683852053087023978010188144107163145164586420445263064724930686003901511627395052659481408547123871407008485127664685784237943462320106826498735373812869875643428632125173297462470986055646835053787867 True </pre> <br /> 역시... 이렇게 확인이 되어야 마음이 놓인다니까요. ^^<br /> <br /> <a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=727&boardid=331301885'>첨부한 파일은 위의 과정을 테스트한 프로젝트</a>입니다.<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
5206
(왼쪽의 숫자를 입력해야 합니다.)