bernie6401
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
# Cryptography and Network Security – Homework 1 [![hackmd-github-sync-badge](https://hackmd.io/Tq2dPdTKQv6p3AvNbmyNig/badge)](https://hackmd.io/Tq2dPdTKQv6p3AvNbmyNig) ###### tags: `NTUCNS` :::spoiler TOC [TOC] ::: :::info [Official Solution](https://hackmd.io/@uqzWTXyyTk6IYTBwcPwnoA/BJZNQfcTo) ::: Student ID: `R11921A16` Name: 何秉學 ## Handwriting ### 1. CIA **Ans:** **Confidentiality** means all of the sensitive messages or information that can be protected so that just the people who have the authentication can edit or browse the information. **Integrity** refers to the completeness of the message you transferred and ensured that the message is not altered by an unauthenticated person. **Availability** means the system must be workable during the service time. In addition, the latency during querying is tolerable and is as short as possible. The real-world instance including these security requirements is the bank duty system. That is, it must be guaranteed that the sensitive message is not accessible during transferring time such as the account information, bank card id, especially the bank card password, etc. Furthermore, the bank system must maintain the completeness of its service such as website service and the querying time must be tolerable. Moreover, it must ensure the data is safe that won't be altered by anybody during transmission. ### 2. Hash Function **Ans:** **one-wayness** means a function $y=f(x)$ is one-way if it is easy to compute $y$ from $x$ but "hard" to compute $x$ from $y$. For instance, it's usually used for password storage and data encryption such as RSA or Diffie-Hellman, to generate keys that are used to encrypt and decrypt data. **weak collision resistance**: For given $m$ then find (compute) a collision $(m, m’)$ is difficult. That is, $h(m)=h(m')$ is hard to find $m'$ when $m$ is given. This objective is for the integrity of data. For instance, it's usually used to verify file integrity or password verification. When the user uploads a file or enters the password, the hash value must be the same as the data stored in the database. **strong collision resistance**: Difficult to find a (some) collision $(m, m’)$. That is, it's difficult(computationally infeasible) to find any two value that has the same hash value. For example, digital signatures and message authentication codes will use this concept to construct the algorithm. This concept can guarantee that the digital signature is unique furthermore, it's infeasible for attackers to find the collision. ### 3. Multi-prime RSA 1. Ans: Assume $c$ is the cipher that encrypted by RSA, $d$ is the inverse of chosen $e$, and $n$ is the multiplication result of two prime. $$ c^d\ mod\ n=(m^e)^d\ mod\ n=m^{ed}\ mod\ n=m^1\ mod\ n=m,\ \because d \equiv e^{-1}\ mod\ \phi(N) $$ 2. Ans: First reason: it's easily to find $p=q=\sqrt{N}$ when $N$ is given. Second reason: when $p=q$, some message that $x∈\{0…N−1\}$ can not be decrypted while $x≡0\ (mod\ p)$. However, this is not a big problem if two prime number is as big as enough. 3. Ans: WLOG, we can use 3-prime number as RSA parameters and we can also use CRT(Chinese Remainder Theorem) to optimize the problem $M \equiv C^d\ (mod\ N)$, where $N=P_1*P_2*P_3$ and also they're pairwise coprime. So, our objective is to find what $M$ is that we just try to decrypt a cipher $C$. Also, we wonder if CRT can optimize the computation process. First, we assume $$ \left\{ \begin{array}{c} x\ \equiv \ m_1\ (mod\ P_1) \\ x\ \equiv \ m_2\ (mod\ P_2) \\ x\ \equiv \ m_3\ (mod\ P_3) \end{array} \right. \ \ and\ \ \left\{ \begin{array}{c} m_1\ \equiv \ C^d\ (mod\ P_1) \\ m_2\ \equiv \ C^d\ (mod\ P_2) \\ m_3\ \equiv \ C^d\ (mod\ P_3) \end{array} \right. $$ Second, we have to compute what is $m_1$, $m_2$, $m_3$ by using Fermat's Little Theorem, which is defined as following: :::info If $P$ is a prime number, then $a^P \equiv a\ (mod\ P)$. If $P$ is a prime number and $a$ is not divisible by $P$, i.e. $a \equiv b\ (mod\ P)\ where\ b \ne 0$, then $a^{P-1} \equiv 1\ (mod\ P)$. ::: $$ \left\{ \begin{array}{c} \begin{aligned} m_1\ &≡ \ C^d\ (mod\ P_1) \\ &≡\ (C^{P_1-1})^{\alpha_1}*C^{\beta_1}\ (mod\ P_1) \\ &≡\ C^{\beta_1}\ (mod\ P_1) \end{aligned} \end{array} \ \because\ (C^{P_1-1})^{\alpha_1}=1 \right. $$ $$ \left\{ \begin{array}{c} \begin{aligned} m_2\ &≡ \ C^d\ (mod\ P_2) \\ &≡\ (C^{P_2-1})^{\alpha_2}*C^{\beta_2}\ (mod\ P_2) \\ &≡\ C^{\beta_2}\ (mod\ P_2) \end{aligned} \end{array} \ \because\ (C^{P_2-1})^{\alpha_2}=1 \right. $$ $$ \left\{ \begin{array}{c} \begin{aligned} m_3\ &≡ \ C^d\ (mod\ P_3) \\ &≡\ (C^{P_3-1})^{\alpha_3}*C^{\beta_3}\ (mod\ P_3) \\ &≡\ C^{\beta_3}\ (mod\ P_3) \end{aligned} \end{array} \ \because\ (C^{P_3-1})^{\alpha_3}=1 \right. $$ Third, we can compute $x$ by using $m_1$, $m_2$, $m_3$ and CRT We compute two of them first. $$ \left\{ \begin{array}{c} x\ \equiv \ m_1\ (mod\ P_1) \\ x\ \equiv \ m_2\ (mod\ P_2) \end{array} \right. $$ At the beginning, we use Euclidean Algorithm to construct $1=aP_1+bP_2$ where $\{a,\ b\} \in \mathbb{Z}$, then $x=aP_1m_2+bP_2m_1+P_1P_2k'$ where $\{a,\ b,\ k'\} \in \mathbb{Z}$ $$x \equiv aP_1m_2+bP_2m_1\ (mod\ P_1P_2)$$ Next, we compute the rest of them and repeat the previous step $$ \left\{ \begin{array}{c} \begin{aligned} x &≡ aP_1m_2+bP_2m_1\ (mod\ P_1P_2) \\ x &≡ \ m_3\ (mod\ P_3) \end{aligned} \end{array} \right. $$ To construct $1=cP_3+dP_1P_2$ by using Euclidean Algorithm then $x=cP_3(aP_1m_2+bP_2m_1)+dP_1P_2m_3+P_1P_2P_3k''$ where $\{a,b,c,d,k',k''\} \in \mathbb{Z}$ And done, the $x$ is uniquely equivalent to $M$ that what we want. --- We can make an instance to prove the correctness. Assume $P_1=3$, $P_2=7$, $P_3=13$ and $n=3×7×13=273$,$φ(n)= 2×6×12=144$,we choose $e=5$,and the inverse of $e$ is $d=29$ Encryption: $c= m^e\ (mod\ n)=18^5\ mod\ 273=135$ Decryption: $m= c^d\ (mod\ n)=135^{29}\ mod\ 273=18$ Now, we use CRT to optimize the computation process Assume $$ \left\{ \begin{array}{c} x\ \equiv \ m_1\ (mod\ 3) \\ x\ \equiv \ m_2\ (mod\ 7) \\ x\ \equiv \ m_3\ (mod\ 13) \end{array} \right. \ \ and\ \ \left\{ \begin{array}{c} m_1\ \equiv \ 135^{29}\ (mod\ 3) \\ m_2\ \equiv \ 135^{29}\ (mod\ 7) \\ m_3\ \equiv \ 135^{29}\ (mod\ 13) \end{array} \right. $$ Then $$ \left\{ \begin{array}{c} \begin{aligned} m_1\ &≡ \ 135^{29}\ (mod\ 3) \\ &≡\ (135^2)^{14}*135^1\ (mod\ 3) \\ &≡\ 135\ (mod\ 3) \\ &≡\ 0\ (mod\ 3) \end{aligned} \end{array} \ \because\ (135^2)^{14}=1 \right. $$ $$ \left\{ \begin{array}{c} \begin{aligned} m_2\ &≡ \ 135^{29}\ (mod\ 7) \\ &≡\ (135^6)^{4}*135^5\ (mod\ 7) \\ &≡\ 2^5\ (mod\ 7) \\ &≡\ 4\ (mod\ 7) \end{aligned} \end{array} \ \because\ (135^6)^{4}=1 \right. $$ $$ \left\{ \begin{array}{c} \begin{aligned} m_3\ &≡ \ 135^{29}\ (mod\ 13) \\ &≡\ (135^{12})^{2}*135^5\ (mod\ 13) \\ &≡\ 5^5\ (mod\ 13) \\ &≡\ 5\ (mod\ 13) \end{aligned} \end{array} \ \because\ (135^{12})^{2}=1 \right. $$ Next, we can start to compute $x$. $$ \left\{ \begin{array}{c} x\ \equiv \ 0\ (mod\ 3) \\ x\ \equiv \ 4\ (mod\ 7) \\ x\ \equiv \ 5\ (mod\ 13) \end{array} \right. $$ We compute 2 of them first. The $gcd(3,7)=1$, so we tried to construct $1=1*7+(-2)*3\ \to$ $$ \begin{aligned} x&=7*1*0+3*(-2)*4+21k\\ &=-24+21k,\ k \in \mathbb{Z}\\ x&\equiv 18\ (mod\ 21) \end{aligned} $$ Then we compute $$ \left\{ \begin{array}{c} x\equiv 18\ (mod\ 21) \\ x\equiv \ 5\ (mod\ 13) \end{array} \right. $$ Repeat previous step, the $gcd(13,21)=1$, then we can construct $1=21*5+13*(-8)$ $$ \begin{aligned} x&=21*5*5+13*(-8)*18+21*13k' \\ &=-1347+273k' \\ x&=18,\ if\ k'=5 \end{aligned} $$ Finally, we decrypt $M=x=18$ successfully by using CRT to optimize the whole computation process. 4. Ans: The advantages of the multi-prime RSA algorithm are mainly manifested in two aspects: 1. It can reduce the calculation amount of key generation. 2. The application of CRT can reduce the calculation amount of decryption and signature. On the other hand, the smaller the prime factor, the easier it is to factorize large numbers. Data published by RSA Laboratories shows that the more prime numbers used, the lower the RSA strength. The following table lists the amount of computation (unit: MIPS·year) required to break the 2-to-multiple prime RSA system. So, here is another disadvantage of multi-prime RSA that requires larger key sizes to achieve the same level of security as regular RSA. This can lead to slower encryption and decryption times and larger storage requirements for keys. | Key Length | 2 Prime Number | 3 Prime Number |4 Prime Number|5 Prime Number| | ---------- | -------- | -------- | --- | --- | |512 bits|$2.1*10^6$|Easy|Very Easy|Very Very Easy| |768 bits|$4.0*10^{11}$|$1.2*10^8$|Easy|Very Easy| |1024 bits|$1.4*10^{16}$|$3.0*10^{11}$|$2.1*10^8$|Easy| |1536 bits|$8.2*10^{23}$|$1.8*10^{17}$|$1.9*10^{13}$|$4.2*10^{10}$| |2048 bits|$3.8*10^{30}$|$1.5*10^{22}$|$3.2*10^{17}$|$2.3*10^{14}$| 5. (skip) ### 4. Fun With Semantic Security I'll prove all these theorem by contrapositive. In addition, the premise of these question is that $E(Enc(k,\ m),\ Dec)$ is $S.S.$(semantic secure), so $|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \le \varepsilon$ Assume $f(\cdot )$ is a guessing function that adversary used to guess $b'$ by the return value from challenger. The model is the same as lecture taught shown as below. Assume $\mathbb{K},\mathbb{M}$ are both group with a binary operation $+$ and $\{k,m\} \xleftarrow{R} (\mathbb{K},\mathbb{M})$ ![](https://i.imgur.com/jBohSG4.png) 1. Ans: Assume $SS_{adv}[B, E']$ is negligible $\implies\ SS_{adv}[A, E]$ is negligible. Therefore, I can use contrapositive to prove if $E(Enc, Dec)$ is not $S.S.\ \implies E'(Enc', Dec')$ is not $S.S.$ as well. Because there must exist a magic function $f(\cdot)$ that can guess $b'$ with high confidence $\varepsilon' \gt \varepsilon$ Assume $c=Enc(k,\ m_b)$ and $E$ is not $S.S.$, then we know $$ \begin{aligned} SS_{adv}[c,\ E]&=|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \\ &=|Pr[b'=1|b=0]-Pr[b'=1|b=1]| \\ &=|Pr[f(c)=1|b=0]-Pr[f(c)=1|b=1]| \\ &=|Pr[f(Enc(k,\ m_b))=1|b=0]-Pr[f(Enc(k,\ m_b))=1|b=1]| \\ &=|Pr[f(Enc(k,\ m_0))=1]-Pr[f(Enc(k,\ m_1))=1]| \gt \varepsilon \end{aligned} $$ But how about $E'$ that defined a new decryption cipher? We also can use the magic function that found in original decryption cipher to address this question. $$ \begin{aligned} SS_{adv}[c,\ E']&=|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \\ &=|Pr[b'=1|b=0]-Pr[b'=1|b=1]| \\ &=|Pr[f(c||r)=1|b=0]-Pr[f(c||r)=1|b=1]| \\ &=|Pr[f(Enc(k,\ m_b)||r)=1|b=0]-Pr[f(Enc(k,\ m_b)||r)=1|b=1]| \end{aligned} $$ Though, we don't know the length of $r$ (i.e. $|r|$), we still can repeat the guessing process while decrease the 1 byte of $c||r$ for each time until the parameter of function $f(\cdot)$ is $|c|$, then I can still aware of the guessing result with high confidence. That is $$ \begin{aligned} SS_{adv}[c,\ E']&=|Pr[f(Enc(k,\ m_b)||r)=1|b=0]-Pr[f(Enc(k,\ m_b)||r)=1|b=1]| \\ &= |Pr[f(Enc(k,\ m_b))=1|b=0]-Pr[f(Enc(k,\ m_b))=1|b=1]| \\ &= |Pr[f(Enc(k,\ m_0))=1]-Pr[f(Enc(k,\ m_1))=1]| \gt \varepsilon \end{aligned} $$ Then, we know that if $E$ is not $S.S.$, then $E'$ is not $S.S.$ as well. In other words, if $E$ is $S.S.$, then $E'$ is $S.S.$ definitely. 2. Ans: Follow the concept above and we assume $m'=m+r$ and $m_b' = m_b+r$. Premise: $E(Enc(k,m), Dec(\cdot))$ is $S.S.$ then $E(Enc(k,m+r), Dec(\cdot))$ is $S.S.$ as well where $r \xleftarrow{R} \mathbb{M}$. Because $\mathbb{M}$ is a group that with a binary operation +, $m+r\in \mathbb{M}$ which means $E(Enc'(k,m_b'),\ Dec(\cdot))$ is $S.S.$ as well. Again, if $E(Enc, Dec)$ is not $S.S.$ then there must exist a magic function $f'(\cdot)$ that can guess $b'$ with high confidence $\varepsilon' \gt \varepsilon$ Assume $c=Enc(k,\ m_b')$ and $E$ is not $S.S.$, then we know $$ \begin{aligned} SS_{adv}[c,\ E]&=|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \\ &=|Pr[b'=1|b=0]-Pr[b'=1|b=1]| \\ &=|Pr[f'(c)=1|b=0]-Pr[f'(c)=1|b=1]| \\ &=|Pr[f'(Enc(k,\ m_b'))=1|b=0]-Pr[f'(Enc(k,\ m_b'))=1|b=1]| \\ &=|Pr[f'(Enc(k,\ m_0'))=1]-Pr[f'(Enc(k,\ m_1'))=1]| \gt \varepsilon \end{aligned} $$ But how about $E'$ that defined a new decryption cipher? We also can use the magic function that found in original decryption cipher to address this question. $$ \begin{aligned} SS_{adv}[c,\ E']&=|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \\ &=|Pr[b'=1|b=0]-Pr[b'=1|b=1]| \\ &=|Pr[f'(Enc'(k,\ m_b+r)||r)=1|b=0]-Pr[f'(Enc'(k,\ m_b+r)||r)=1|b=1]| \end{aligned} $$ Again, we don't know $|r|$, we still can repeat the guessing process while decrease the 1 byte of $c||r$ for each time (i.e. $f'([Enc'(k,m_b')||r][:-j])$ where $j=\{1,\cdots,|r|\}$). In a word, $$ \begin{aligned} SS_{adv}[c,\ E']&=|Pr[f'(Enc(k,\ m_b')||r)=1|b=0]-Pr[f'(Enc'(k,\ m_b')||r)=1|b=1]| \\ &= |Pr[f'(Enc(k,\ m_b'))=1|b=0]-Pr[f'(Enc(k,\ m_b'))=1|b=1]| \\ &= |Pr[f'(Enc(k,\ m_0'))=1]-Pr[f'(Enc(k,\ m_1'))=1]| \gt \varepsilon \end{aligned} $$ Then, we know that if $E$ is not $S.S.$, then $E'$ is not $S.S.$ as well. In other words, if $E$ is $S.S.$, then $E'$ is $S.S.$ definitely. 3. Ans: Follow the concept of previous 2 questions and we assume $k'=k+r$. Premise: $E(Enc(k,m), Dec(\cdot))$ is $S.S.$ then $E(Enc(k+r,m), Dec(\cdot))$ is $S.S.$ as well where $r \xleftarrow{R} \mathbb{K}$. Because $\mathbb{K}$ is a group that with a binary operation +, $k+r\in \mathbb{K}$ which means $E(Enc'(k',m_b),\ Dec(\cdot))$ is $S.S.$ as well. Again, if $E(Enc, Dec)$ is not $S.S.$ then there must exist a magic function $f''(\cdot)$ that can guess $b'$ with high confidence $\varepsilon' \gt \varepsilon$ Assume $c=Enc(k',\ m_b)$ and $E$ is not $S.S.$, then we know $$ \begin{aligned} SS_{adv}[c,\ E]&=|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \\ &=|Pr[b'=1|b=0]-Pr[b'=1|b=1]| \\ &=|Pr[f''(c)=1|b=0]-Pr[f''(c)=1|b=1]| \\ &=|Pr[f''(Enc(k',\ m_b))=1|b=0]-Pr[f''(Enc(k',\ m_b))=1|b=1]| \\ &=|Pr[f''(Enc(k',\ m_0))=1]-Pr[f''(Enc(k',\ m_1))=1]| \gt \varepsilon \end{aligned} $$ But how about $E'$ that defined a new decryption cipher? We also can use the magic function that found in original decryption cipher to address this question. $$ \begin{aligned} SS_{adv}[c,\ E']&=|Pr[Exp^{SS}(0)=1]-Pr[Exp^{SS}(1)=1]| \\ &=|Pr[b'=1|b=0]-Pr[b'=1|b=1]| \\ &=|Pr[f''(Enc'(k',\ m_b)||r)=1|b=0]-Pr[f''(Enc'(k',\ m_b)||r)=1|b=1]| \end{aligned} $$ Again, we don't know $|r|$, we still can repeat the guessing process while decrease the 1 byte of $c||r$ for each time (i.e. $f'([Enc'(k,m_b')||r][:-j])$ where $j=\{1,\cdots,|r|\}$). In a word, $$ \begin{aligned} SS_{adv}[c,\ E']&=|Pr[f''(Enc(k',\ m_b)||r)=1|b=0]-Pr[f''(Enc'(k',\ m_b)||r)=1|b=1]| \\ &= |Pr[f''(Enc(k',\ m_b))=1|b=0]-Pr[f''(Enc(k',\ m_b))=1|b=1]| \\ &= |Pr[f''(Enc(k',\ m_0))=1]-Pr[f''(Enc(k',\ m_1))=1]| \gt \varepsilon \end{aligned} $$ Then, we know that if $E$ is not $S.S.$, then $E'$ is not $S.S.$ as well. In other words, if $E$ is $S.S.$, then $E'$ is $S.S.$ definitely. ## CTF ### 5. Simple Crypto #### Recon * Round 1 Just simple ROT-13 * Round 2 Just simple rail fence cipher * Round 3 Can observe that the question gave the `b64encode(c1)` and `m1` and we need to decrypt to `m2` using `b64encode(c2)` it gave us. I thought about it for a long time. It seems one-time-pad reused problem. Because the length of `b64encode(c1)` and `m1` are the same. So, I `xor` them and get the key. In addition, I repeated the operation that `xor` `b64encode(c2)` and key then I got the plain text message. The whole script is as below. The attack can be success only if the length of `b64encode(c1)` greater than the length of `b64encode(c2)`. It means we can get enough key to decrypt `c2`, otherwise, the plain text is incomplete. * Round 4 Hint 1: One-layer fence is not solid enough, how about two? Hint 2: You can safely ignore all white spaces and punctuation marks. 1. You can observe that every time the cipher is just changed the capital of the letter and the semantic sentence is preserved. So, we can assume that it encrypt every bits in alphabetic with its upper or lower letter(i.e. upper letter is represented to 1, otherwise, is represented to 0). Therefore, you can use the script below to transfer every character to binary. 2. After the conversion, the length of the binary is $155$, it means we have to find something like morse code to decode it. At the beginning, my perspective is baudot code that encrypt/decrypt the code with every 5 bits. This is perfectly coincide the factor of $155$, however, nothing plaintext-like string appeared. Then I continued looking for another baudot-like cipher. The answer is bacon cipher that similar to baudot which is also encrypt/decrypt the code with every 5 bits. 3. After the conversion, the string was still incorrect. So, I tried various methods to decrypt it. Then I think the this question mentioned fence again that means this is the advanced fence question that I should address. Therefore, I tried rail fence cipher again to decrypt it to semantic meaningful string(means I can read it as normal English). #### Exploit * Round 1 [ROT-Based online solver](https://gchq.github.io/CyberChef/#recipe=ROT13(true,true,false,5)&input=RGlham1odm9kamktb2N6am16b2R4dmdndCBuenhwbXo) * Round 2 [Rail Fense Cipher online solver](https://gchq.github.io/CyberChef/#recipe=Rail_Fence_Cipher_Decode(5,0)) * Round 3 One-Time-Pad * Round 4 Binary encrypt in Alphabetic → Bacon Cipher → Rail Fence Cipher 4-1. Alphabet → Binary Alphabet → Binary ```python import re ciphertext = input("Cipher Text of Round 4: ") ciphertext = ciphertext.replace('!', '').replace(',', '').replace('.', '').replace(' ', '') plaintext = '' for i in range(len(ciphertext)): plaintext += 'A' if re.search(r"[a-z]", ciphertext[i]) else 'B' # print(plaintext) for i in range(0, len(plaintext), 5): print(plaintext[i:i+5], end=" ") ``` 4-2. [Bacon Cipher](https://gchq.github.io/CyberChef/#recipe=Bacon_Cipher_Decode('Standard%20(I%3DJ%20and%20U%3DV)','0/1',false)) 4-3. [Rail Fense Cipher online solver](https://gchq.github.io/CyberChef/#recipe=Rail_Fence_Cipher_Decode(5,0)) * Round 5 Base64 decode Flag 5: `CNS{5upeR_3asy_c1a55ic@l_cryp70!}` ### 6. ElGamal Cryptosystem #### Recon 1. 6-1 ![](https://i.imgur.com/2gSBJin.png) As the screenshot above, seems it reused $a$ that it should be chosen randomly. Thus, as the algorithm taught on class $$c_1=c_1'=(self.g)^y\ (mod\ self.P)$$ $$c_2=(self.pk)^y\ (mod\ self.P)\ *\ flag1\ (mod\ self.P)$$ $$c_2=(self.pk)^y\ (mod\ self.P)\ *\ m_2\ (mod\ self.P)$$ 2. 6-2 3. 6-3 Keys quantities: 5 Threshold: 5(That means the user needs $5$ keys to generate the secret(constant term of the formula) #### Exploit 1. 6-1 $$tmp = (self.pk)^y\ (mod\ self.P)=c_2'*inverse(m_2,\ self.P)\ \%\ self.P$$ $$flag1 = c_2*inverse(tmp,\ self.P)\ \%\ self.P$$ ::: spoiler source code ```python= from pwn import * from Crypto.Util.number import bytes_to_long, long_to_bytes from Crypto.Util.number import inverse r = remote('cns.csie.org', 6001) context.arch = 'amd64' r.recvuntil(b"P = ") p = int(r.recvline().strip().decode()) r.recvuntil(b"g = ") g = int(r.recvline().strip().decode()) r.recvuntil(b"cipher = (") c1 = int(r.recvuntil(b", ").decode().replace(", ", "")) c2 = int(r.recvuntil(b")").decode().replace(")", "")) log.info("P = {}".format(p)) log.info("g = {}".format(g)) log.info("c1 = {}".format(c1)) log.info("c2 = {}".format(c2)) m2 = '1' r.recvuntil(b"Do you want to encrypt something? (y/n): ") r.sendline(b'y') r.recvuntil(b"Give me your message: ") r.sendline(m2.encode()) r.recvuntil(b"Your cyphertext (") c1_ = int(r.recvuntil(b", ").decode().replace(", ", "")) c2_ = int(r.recvuntil(b")").decode().replace(")", "")) log.info("c1\' = {}".format(c1_)) log.info("c2\' = {}".format(c2_)) m2 = bytes_to_long(m2.encode()) log.info("m2 = {}".format(m2)) tmp = c2_ * inverse(m2, p) % p flag = c2 * inverse(tmp, p) % p flag = bytes.fromhex(hex(flag).replace('0x', "")).decode('utf-8') log.info(flag) r.close() r.interactive() ``` ::: Flag 6-1: `CNS{n0_r3us3d_3ph3m3ra1_K3Y!}` 2. 6-2(Bonus) 3. 6-3 Assume: $$m_n={c_1}^{f(n)}\ (mod\ self.P),\ n\in\{1,...,5\}$$where $self.P$ is a group defined by author, $c_1$ is the user-chosen string that should be decrypted So, I can put each of the response from the server into `Lagrange Interpolation Formula`, that is $$ \begin{aligned} f(x)&=ax^4+bx^3+cx^2+dx+sk\\ &=f(1){(x-x_2)(x-x_3)(x-x_4)(x-x_5) \over (x_1-x_2)(x_1-x_3)(x_1-x_4)(x_1-x_5)} \\ &+ f(2){(x-x_1)(x-x_3)(x-x_4)(x-x_5) \over (x_2-x_1)(x_2-x_3)(x_2-x_4)(x_2-x_5)} \\ &+ f(3){(x-x_1)(x-x_2)(x-x_4)(x-x_5) \over (x_3-x_1)(x_3-x_2)(x_3-x_4)(x_3-x_5)} \\ &+ f(4){(x-x_1)(x-x_2)(x-x_3)(x-x_5) \over (x_4-x_1)(x_4-x_2)(x_4-x_3)(x_4-x_5)} \\ &+ f(5){(x-x_1)(x-x_2)(x-x_3)(x-x_4) \over (x_5-x_1)(x_5-x_2)(x_5-x_3)(x_5-x_4)} \end{aligned} $$ Then if we wonder $sk$ at the constant of the formula, we can put $x=0,\ x_1=1,\ x_2=2,\ x_3=3,\ x_4=4,\ x_5=5$ into function, that is $$f(0)=5f(1)-10f(2)+10f(3)-5f(4)+f(5)=sk$$ $$c_1^{sk}=m_1^5*inverse(m_2^{10},\ self.P)*m_3^{10}*inverse(m_4^5,\ self.P)*m_5$$ :::info Note that, we can set $c_1=C1$ which is one return value from `ElGamal Encryption`: $\{C1, C2\} \leftarrow en_{ElGamal}(randomeNumber, message)$ ::: So, the flag is: $$ \begin{aligned} flag &= C2*[inverse(C1, self.P)]^{sk}\ \% \ self.P\\ &= C2*[inverse(C1^{sk}, self.P)]\ \% \ self.P \\ &= C2*[inverse(c_1^{sk}, self.P)]\ \% \ self.P \end{aligned} $$ :::spoiler 6-3 source code ```python= from pwn import * from Crypto.Util.number import bytes_to_long, long_to_bytes from Crypto.Util.number import inverse r = remote('cns.csie.org', 6003) context.arch = 'amd64' r.recvuntil(b"P = ") p = int(r.recvline().strip().decode()) r.recvuntil(b"g = ") g = int(r.recvline().strip().decode()) r.recvuntil(b"cipher = (") c1 = int(r.recvuntil(b", ").decode().replace(", ", "")) c2 = int(r.recvuntil(b")\n").decode().replace(")\n", "")) log.info("P = {}".format(p)) log.info("g = {}".format(g)) log.info("c1 = {}".format(c1)) log.info("c2 = {}".format(c2)) message_user_input = str(c1) m = [] # print(r.recvline()) for i in range(1, 6): r.recvuntil(b'Do you want to decrypt something? (y/n): ') r.sendline(b'y') r.recvuntil(b'Give me your c1: ') r.sendline(message_user_input.encode()) r.recvuntil(b'(1~5): ') # r.recvline() r.sendline(str(i).encode()) m.append(int(r.recvline().decode())) log.info("m{} = {}".format(i, m[-1])) tmp = ((m[0]**5)*inverse(m[1]**10, p)*(m[2]**10)*inverse(m[3]**5, p)*m[4]) % p flag = bytes.fromhex(long_to_bytes((c2 * inverse(tmp, p)) % p).hex().replace("0x", "")).decode('utf-8') log.info(flag) r.close() ``` ::: Flag 6-3: `CNS{l4gr4ng3_P0lyn0m14L_12_s0_34SY}` :::danger It may not work sometimes, so, please re-run it again ::: ### 7. Bank #### Recon If I register an account, I earn `$10`. In addition, If the register name contain `I love CNS`, I can earn `$15` that `$5` for extra. Obviously, I should find SHA-1 collision for earning extra money to buy the flag. The main flow is like: 1. Find a string that have SHA-1 collision(assume A and B) 2. Register A account and login to earn `$10` then logout 3. Register B account 4. Login by B account 5. At this moment, the money will be saved in A account due to collision 6. Then logout and re-login A account and buy the flag(now A account should have `$20`) #### Essential Source Code ```python=116 ... match cmd: case 1: # register username = input_untruncated("Username: ").strip(b"\n") if username in keys: print("The username already used, try another") continue key = keys[username] = random.randbytes(16) print( f"Here is your passkey, store it in a safe place: {base64.b64encode(key).decode()}" ) h = sha1(username) balances[h] += NEW_USER_GIFT if b"I love CNS" in username: # good students get bonus balances[h] += CNS_LOVER_BONUS ... ``` #### Exploit Just find the collision of SHA-1 :::spoiler source code ```python from pwn import * context.arch = 'amd64' for i in range(2): # r = process('./server.py') r = remote('cns.csie.org', 44377) magic1 = open('shattered-1.pdf', 'rb').read() + b'I love CNS' magic2 = open('shattered-2.pdf', 'rb').read() + b'I love CNS' '''Register "I love CNS and get the passkey"''' r.recvuntil(b'Your choice: ') r.sendline(b'1') r.recvuntil(b'Username: ') r.sendline(magic1) passkey = r.recvline().decode('utf-8').split(': ')[1].replace('\n', '') log.info("Normal account passkey: {}".format(passkey)) '''Register another account that has same sha1 value with previous one''' r.recvuntil(b'Your choice: ') r.sendline(b'1') r.recvuntil(b'Username: ') r.sendline(magic2) passkey_collision = r.recvline().decode('utf-8').split(': ')[1].replace('\n', '') log.info("Collision account passkey: {}".format(passkey_collision)) '''Login Normal Account and Get money''' r.recvuntil(b'Your choice: ') r.sendline(b'2') r.recvuntil(b'Username: ') r.sendline(magic1) r.recvuntil(b'Passkey in Base64: ') r.sendline(passkey.encode()) '''Logout''' r.recvuntil(b'Your choice: ') r.sendline(b'1') '''Login Collision Account''' r.recvuntil(b'Your choice: ') r.sendline(b'2') r.recvuntil(b'Username: ') r.sendline(magic2) r.recvuntil(b'Passkey in Base64: ') r.sendline(passkey_collision.encode()) '''Logout''' r.recvuntil(b'Your choice: ') r.sendline(b'1') '''Login Normal Account and Get money''' r.recvuntil(b'Your choice: ') r.sendline(b'2') r.recvuntil(b'Username: ') r.sendline(magic1) r.recvuntil(b'Passkey in Base64: ') r.sendline(passkey.encode()) r.recvuntil(b'You have $') money = r.recvline().decode().split(" ")[0] log.info("Your money is: {}".format(money)) r.recvuntil(b'Your choice: ') if i == 0: r.sendline(b'2') r.recvuntil(b'Here is your flag 1:') flag1 = r.recvline().strip().decode() log.info("Flag1: {}".format(flag1)) elif i == 1: r.sendline(b'3') r.recvuntil(b'Here is your flag 2:') flag2 = r.recvline().strip().decode() log.info("Flag2: {}".format(flag2)) r.close() r.interactive() ``` ::: Flag 7-1: `CNS{ha$h_i5_m15used}` Flag 7-2: `CNS{$ha1_15_n0t_c0ll1510n_r3s1st@nt}` ### 8. Clandestine Operation #### Recon 1. Encrypted by AES 2. Mode: CBC 3. Padding type: `PKCS#7` 4. Padding Oracle Attack * ::: spoiler Seems padding oracle `menus.py/askNahida()` ```python=22 ... if choice == 1: ID = input('Please give me the ID (hex encoded): ').strip() try: decrypt(ID) print('Hint: It seems feasible...') except Exception as e: if e.__class__.__name__ == 'UnicodeDecodeError': print('Hint:', 'Not a valid ID...') else: print('Hint:', e) ... ``` `cryptoFunc.py` ```python=11 def unpad(c): length = c[-1] for char in c[-length:]: if char != length: raise paddingError('incorrect padding') return c[:-length] def decrypt(c): aes = AES.new(secret.key, AES.MODE_CBC, secret.iv) return unpad(aes.decrypt(binascii.unhexlify(c))).decode() ... ``` ::: #### Exploit Just padding oracle attack :::spoiler 8-1 source code ```python= from pwn import * from tqdm import trange from itertools import cycle r = remote('cns.csie.org', 44399) context.arch = 'amd64' r.recvuntil(b'Your choice:') r.sendline(b'2') def test_validity(response, error): padding_correct = True if error != response else False return padding_correct def split_len(seq, length): return [seq[i : i + length] for i in range(0, len(seq), length)] def block_search_byte(size_block, i, pos, l): # If ct_pos = 10 and # i = 0 return: 0000000000000000000000000000000a # i = 1 return: 00000000000000000000000000000a # i = 2 return: 000000000000000000000000000a # ... # i = 15 return: 0a hex_char = hex(pos).split("0x")[1] return ("00" * (size_block - (i + 1)) + ("0" if len(hex_char) % 2 != 0 else "") + hex_char + "".join(l)) def block_padding(size_block, i): # It'll return # '00000000000000000000000000000001' # '00000000000000000000000000000202' # '00000000000000000000000000030303' # ... # '10101010101010101010101010101010' l = [] for t in range(0, i + 1): l.append(("0" if len(hex(i + 1).split("0x")[1]) % 2 != 0 else "") + (hex(i + 1).split("0x")[1])) return "00" * (size_block - (i + 1)) + "".join(l) def hex_xor(s1, s2): b = bytearray() for c1, c2 in zip(bytes.fromhex(s1), cycle(bytes.fromhex(s2))): b.append(c1 ^ c2) return b.hex() def call_oracle(tmp_ID): r.recvuntil(b'Your choice:') r.sendline(b'1') r.recvuntil(b'Please give me the ID (hex encoded): ') # print(tmp_ID) r.sendline(tmp_ID.encode()) return r.recvline().strip().decode() cipher = '70309f98653e87df804263d5a0348f115c36bc7c2cddfe02ffd44528083635404815ed8c0f14ad8cbbb1c7bc12bf21725fa15c0e7ba326e433ec41ddfaf41d27aa18ce4381a61d187ecbdcc9740747d300b7f354bb68139f2306508a06a04fbe' found = False valide_value = [] result = [] size_block = 16 len_block = size_block * 2 cipher_block = split_len(cipher, len_block) error = 'Hint: PADDING ERROR : incorrect padding' if len(cipher_block) == 1: print("[-] Abort there is only one block") sys.exit() # for each cipher_block for block in reversed(range(1, len(cipher_block))): if len(cipher_block[block]) != len_block: print("[-] Abort length block doesn't match the size_block") break print("[+] Search value block : ", block, "\n") # for each byte of the block for i in range(0, size_block): # test each byte max 255 for ct_pos in range(0, 256): # 1 xor 1 = 0 or valide padding need to be checked if ct_pos != i + 1 or ( len(valide_value) > 0 and int(valide_value[-1], 16) == ct_pos ): bk = block_search_byte(size_block, i, ct_pos, valide_value) bp = cipher_block[block - 1] bc = block_padding(size_block, i) tmp = hex_xor(bk, bp) # print(bk) cb = hex_xor(tmp, bc) if block == 5: up_cipher = cipher_block[0] + cipher_block[1] + cipher_block[2] + cipher_block[3] + cb + cipher_block[5] elif block == 4: up_cipher = cipher_block[0] + cipher_block[1] + cipher_block[2] + cb + cipher_block[4] elif block == 3: up_cipher = cipher_block[0] + cipher_block[1] + cb + cipher_block[3] elif block == 2: up_cipher = cipher_block[0] + cb + cipher_block[2] else: up_cipher = cb + cipher_block[1] # we call the oracle, our god response = call_oracle( up_cipher ) if test_validity(response, error): found = True print(up_cipher) # data analyse and insert in right order value = re.findall("..", bk) valide_value.insert(0, value[size_block - (i + 1)]) bytes_found = "".join(valide_value) if ( i == 0 and int(bytes_found, 16) > size_block and block == len(cipher_block) - 1 ): print( "[-] Error decryption failed the padding is > " + str(size_block) ) sys.exit() print( "\033[36m" + "\033[1m" + "[+]" + "\033[0m" + " Found", i + 1, "bytes :", bytes_found, ) print("") break if found == False: # lets say padding is 01 for the last byte of the last block (the padding block) if len(cipher_block) - 1 == block and i == 0: value = re.findall("..", bk) valide_value.insert(0, "01") else: print("\n[-] Error decryption failed") result.insert(0, "".join(valide_value)) hex_r = "".join(result) print("[+] Partial Decrypted value (HEX):", hex_r.upper()) padding = int(hex_r[len(hex_r) - 2 : len(hex_r)], 16) print( "[+] Partial Decrypted value (ASCII):", bytes.fromhex(hex_r[0 : -(padding * 2)]).decode(), ) sys.exit() found = False result.insert(0, "".join(valide_value)) valide_value = [] print("") hex_r = "".join(result) print("[+] Decrypted value (HEX):", hex_r.upper()) padding = int(hex_r[len(hex_r) - 2 : len(hex_r)], 16) print("[+] Decrypted value (ASCII):", bytes.fromhex(hex_r[0 : -(padding * 2)]).decode(),) r.interactive() ``` ::: Flag 8-1: `CNS{Aka_BIT_f1ipp1N9_atTaCk!}` --- In plaintext of `69...` block, we need to tamper specific bytes like(`Cyno` $\to$ `Azar`). We can xor the previous ciphertext block(`5c...`) ```bash! >>> m1 = 'Cyno'.encode('utf-8').hex() >>> m2 = 'Azar'.encode('utf-8').hex() >>> hex(int(m1,16)^int(m2,16)) '0x2030f1d' >>> hex(int('28083635',16)^int('2030f1d',16)) '0x2a0b3928' ``` So, the `xor_patch` is `0x2030f1d` that we have to xor to the cipher block, `5c...`. And we got ![](https://imgur.com/wzdc8WN.png) :::spoiler 8-2 source code ```python= from pwn import * from tqdm import trange from itertools import cycle from tqdm import trange r = remote('cns.csie.org', 44399) context.arch = 'amd64' r.recvuntil(b'Your choice:') r.sendline(b'1') r.recvuntil(b'Please speak out the secret word: ') r.sendline(b'CNS{Aka_BIT_f1ipp1N9_atTaCk!}') # Try to find the magic number to fit the decryption decode process properly # for i in trange(0, 2**16): # r.recvuntil(b'Your choice:') # r.sendline(b'1') # r.recvuntil(b'Please enter your ID (hex encoded): ') # ID_prefix = '70309f98653e87df804263d5a0348f11' # ID_fake_1 = '{0:0>4x}'.format(i) # ID_fake_2 = 'bc7c2cddfe02ffd445' #5C36 # # print(ID_fake_2) # ID_fake_3 = '2a0b392840' # XOR_Patch # ID_postfix = '4815ed8c0f14ad8cbbb1c7bc12bf21725fa15c0e7ba326e433ec41ddfaf41d27aa18ce4381a61d187ecbdcc9740747d300b7f354bb68139f2306508a06a04fbe' # r.sendline((ID_prefix + ID_fake_1 + ID_fake_2 + ID_fake_3 + ID_postfix).encode()) # response = r.recvline().strip().decode() # # print(response) # if 'Authentication failed' not in response and i != 23606: # log.info("The magic number is: {}".format(i)) # print(ID_prefix + ID_fake_1 + ID_fake_2 + ID_fake_3 + ID_postfix) # print(response) # break ''' The magic number is 11065(Decimal) ''' r.recvuntil(b'Your choice:') r.sendline(b'1') r.recvuntil(b'Please enter your ID (hex encoded): ') ID_prefix = '70309f98653e87df804263d5a0348f11' ID_fake_1 = '{0:0>4x}'.format(11065) ID_fake_2 = 'bc7c2cddfe02ffd445' #5C36 ID_fake_3 = '2a0b392840' # XOR_Patch ID_postfix = '4815ed8c0f14ad8cbbb1c7bc12bf21725fa15c0e7ba326e433ec41ddfaf41d27aa18ce4381a61d187ecbdcc9740747d300b7f354bb68139f2306508a06a04fbe' r.sendline((ID_prefix + ID_fake_1 + ID_fake_2 + ID_fake_3 + ID_postfix).encode()) r.recvline() flag = r.recvline().strip().decode().split('. ')[-1] log.info("flag = {}".format(flag)) ``` ::: Flag 8-2: `CNS{W15h_y0U_hav3_a_n1c3_d@y!}` ## Reference ### Multi-prime RSA [多素数RSA系统简介](https://blog.csdn.net/bhw98/article/details/19676) [Why should the primes used in RSA be distinct?](https://crypto.stackexchange.com/questions/26861/why-should-the-primes-used-in-rsa-be-distinct) [利用CRT加速RSA解密](https://youtu.be/NkvCZ8qJ34w?t=4203) [What is multi-prime RSA (RSA-MP)?](https://crypto.stackexchange.com/questions/67043/what-is-multi-prime-rsa-rsa-mp) --- ### Classic [MAC訊息驗證碼](https://ithelp.ithome.com.tw/articles/10188333) [密碼雜湊函式](https://zh.wikipedia.org/wiki/%E5%AF%86%E7%A2%BC%E9%9B%9C%E6%B9%8A%E5%87%BD%E6%95%B8) [Diffie-Hellman](http://www.tsnien.idv.tw/Security_WebBook/chap3/3-6%20Diffie-Hellman%20%E9%91%B0%E5%8C%99%E4%BA%A4%E6%8F%9B%E6%B3%95.html) [Linux匹配文字grep指令用法教學與範例](https://blog.gtwang.org/linux/linux-grep-command-tutorial-examples/) [How can I split multiple joined words?](https://stackoverflow.com/questions/195010/how-can-i-split-multiple-joined-words) [subprocess --- Subprocess management](https://docs.python.org/zh-tw/3.7/library/subprocess.html) [How to Check SHA1 Hash of a String](https://osxdaily.com/2012/06/06/check-sha1-hash-of-string/) --- ### ElGamal Cryptosystem [Known plaintext attack on ElGamal encryption](https://crypto.stackexchange.com/questions/18362/known-plaintext-attack-on-elgamal-encryption?newreg=56d9dd5e0e4e4270854809dd8c47eeca) --- ### Bank [長度擴充攻擊 | Length Extension Attack (LEA)](https://maojui.me/Crypto/LEA/) [SHA-1 psuedo code](https://zh.wikipedia.org/wiki/SHA-1#SHA-0%E7%9A%84%E7%A0%B4%E8%A7%A3) [LEA-CTF實例](https://github.com/oalieno/Crypto-Course/tree/9430c4dcb3b1666098a84b37d4c2122205003609/HASH/Length-Extension-Attack) [HashPump教學](https://www.cnblogs.com/pcat/p/5478509.html) [淺談HASH長度擴充攻擊](https://iter01.com/525343.html) [SHA-1 is a Shambles](https://sha-mbles.github.io/) --- ### Clandestine Operation: [Padding Oracle Attack - github](https://github.com/mpgn/Padding-oracle-attack/blob/master/exploit.py) [[2022 fall] 0923 Crypto](https://youtu.be/hnXtaiyvQ3s?t=7801)

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully